<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Bash Пайпы: Полный Гайд и Шпаргалка]]></title><description><![CDATA[<p dir="auto">Представьте, что вам нужно найти количество файлов в директории. Без пайпов пришлось бы делать так:</p>
<pre><code class="language-bash"># Сначала список файлов сохраняем в файл
ls -l &gt; /tmp/files.txt

# Потом считаем строки
wc -l /tmp/files.txt

# Потом удаляем временный файл
rm /tmp/files.txt
</code></pre>
<p dir="auto">Три команды, временный файл, неудобно.</p>
<h3>Решение с пайпами</h3>
<p dir="auto">С пайпом это становится одной строкой:</p>
<pre><code class="language-bash">ls -l | wc -l
</code></pre>
<p dir="auto"><strong>Почему пайпы полезны:</strong></p>
<ol>
<li><strong>Эффективность</strong> — не нужны временные файлы на диске</li>
<li><strong>Скорость</strong> — данные передаются через оперативную память (быстрее, чем I/O на диск)</li>
<li><strong>Читаемость</strong> — понимаете логику цепочки команд с первого взгляда</li>
<li><strong>Масштабируемость</strong> — можете соединять сколько угодно команд в цепочку</li>
<li><strong>Unix философия</strong> — “Делай одно, делай хорошо” — пайпы объединяют маленькие команды в мощные решения</li>
</ol>
<hr />
<h2>2. Основные концепции: потоки данных</h2>
<p dir="auto">В Linux каждый процесс имеет три стандартных потока:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Поток</th>
<th>Номер FD</th>
<th>Описание</th>
<th>По умолчанию</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>stdin</strong></td>
<td>0</td>
<td>Стандартный ввод (входит в процесс)</td>
<td>Клавиатура</td>
</tr>
<tr>
<td><strong>stdout</strong></td>
<td>1</td>
<td>Стандартный вывод (выходит из процесса)</td>
<td>Экран</td>
</tr>
<tr>
<td><strong>stderr</strong></td>
<td>2</td>
<td>Стандартная ошибка (сообщения об ошибках)</td>
<td>Экран</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>Визуально:</strong></p>
<pre><code>┌─────────────────┐
│     Процесс     │
│                 │
│  ┌──────────┐   │
│  │ команда  │   │
│  └──────────┘   │
│    ↑  ↓  ↓      │
│    │  │  │      │
│    0  1  2      │ (file descriptors)
│    │  │  │      │
└────┼──┼──┼──────┘
     │  │  └─ stderr → экран
     │  └──── stdout → экран
     └─────── stdin ← клавиатура
</code></pre>
<hr />
<h2>3. Как работают пайпы?</h2>
<h3>Механизм пайпа</h3>
<p dir="auto">Пайп (|) соединяет stdout одной команды со stdin другой:</p>
<pre><code>команда1 | команда2
    ↓
stdout(команда1) → stdin(команда2)
</code></pre>
<p dir="auto"><strong>На системном уровне:</strong></p>
<ol>
<li>Shell видит символ <code>|</code> и создаёт канал (pipe) в памяти</li>
<li>Stdout первого процесса подключается к этому каналу</li>
<li>Stdin второго процесса подключается к этому каналу</li>
<li>Обе команды запускаются <strong>одновременно</strong> (параллельно!)</li>
<li>Буферизация позволяет команде 2 работать, пока команда 1 пишет</li>
</ol>
<p dir="auto"><strong>Важно:</strong> Команды выполняются параллельно, но синхронизированы потоком данных.</p>
<h3>Пример в реальном времени</h3>
<pre><code class="language-bash"># Медленный процесс производит данные
(while true; do date; sleep 1; done) | \
# Быстрый процесс их обрабатывает
(while read line; do echo "&gt;&gt;&gt; $line"; done)
</code></pre>
<p dir="auto">Обе команды работают одновременно!</p>
<hr />
<h2>4. Редирекция потоков</h2>
<h3>Базовая редирекция stdout</h3>
<pre><code class="language-bash"># Перенаправить вывод в файл (перезаписать)
command &gt; file.txt

# Добавить в конец файла
command &gt;&gt; file.txt

# Отправить в /dev/null (удалить вывод)
command &gt; /dev/null
</code></pre>
<h3>Редирекция stderr</h3>
<pre><code class="language-bash"># Отправить ошибки в файл
command 2&gt; errors.txt

# Отправить ошибки в файл (классическая форма)
command 2&gt; /tmp/errors.log

# Объединить stderr со stdout
command 2&gt;&amp;1

# Отправить оба потока в файл (современный синтаксис)
command &amp;&gt; output.txt

# Скрыть ошибки
command 2&gt; /dev/null
</code></pre>
<h3>Комбинированная редирекция</h3>
<pre><code class="language-bash"># stdout → файл, stderr → экран
command &gt; output.txt 2&gt;&amp;1

# stdout → одна команда, stderr → другая команда
command 1&gt; &gt;(process_stdout) 2&gt; &gt;(process_stderr)

# Отправить оба потока в разные файлы
command &gt; stdout.txt 2&gt; stderr.txt

# stdout в файл, stderr к stdout, затем в пайп
command 2&gt;&amp;1 | tee output.txt
</code></pre>
<p dir="auto"><strong>Важно про порядок!</strong> Обработка идёт слева направо:</p>
<pre><code class="language-bash"># ПРАВИЛЬНО: сначала объединяем потоки, потом пайпим
command 2&gt;&amp;1 | grep error

# НЕПРАВИЛЬНО: пайпим только stdout
command | grep error 2&gt;&amp;1  # ошибки не попадут в пайп!
</code></pre>
<h3>Редирекция stdin</h3>
<pre><code class="language-bash"># Передать файл как стандартный ввод
command &lt; input.txt

# Передать строку как стандартный ввод
cat &lt;&lt;EOF | command
множественные
строки
текста
EOF
</code></pre>
<hr />
<h2>5. Практические примеры</h2>
<h3>Пример 1: Поиск и подсчёт файлов</h3>
<pre><code class="language-bash"># Найти все .log файлы, созданные за последние 7 дней, и посчитать их
find . -name "*.log" -mtime -7 | wc -l

# Поток данных:
# find → (список файлов в stdin) → wc
</code></pre>
<h3>Пример 2: Фильтрация логов</h3>
<pre><code class="language-bash"># Найти ошибки в логе, исключить DEBUG, показать последние 10
cat app.log | \
  grep "ERROR" | \
  grep -v "DEBUG" | \
  tail -10

# Или более компактно:
grep "ERROR" app.log | grep -v "DEBUG" | tail -10
</code></pre>
<h3>Пример 3: Обработка данных с преобразованием</h3>
<pre><code class="language-bash"># Получить список портов, которые слушают, отсортировать и посчитать уникальные
netstat -tlnp | \
  awk '{print $4}' | \
  cut -d: -f2 | \
  sort | \
  uniq -c | \
  sort -rn
</code></pre>
<p dir="auto"><strong>Разбор:</strong></p>
<ul>
<li><code>netstat -tlnp</code> — показать все слушающие TCP порты</li>
<li><code>awk '{print $4}'</code> — извлечь 4-е поле (адрес:порт)</li>
<li><code>cut -d: -f2</code> — вырезать только номер порта</li>
<li><code>sort</code> — отсортировать</li>
<li><code>uniq -c</code> — посчитать одинаковые</li>
<li><code>sort -rn</code> — отсортировать по убыванию</li>
</ul>
<h3>Пример 4: Обработка JSON</h3>
<pre><code class="language-bash"># Получить все email'ы из JSON API и сохранить в файл
curl -s https://api.example.com/users | \
  jq '.users[].email' | \
  tr -d '"' | \
  sort | \
  uniq &gt; emails.txt
</code></pre>
<h3>Пример 5: Массовая переименование файлов</h3>
<pre><code class="language-bash"># Переименовать все .jpg в .png расширение
ls *.jpg | \
  awk '{print "mv " $1 " " substr($1, 1, length($1)-3) "png"}' | \
  bash

# Или более безопасно (echo для проверки):
ls *.jpg | \
  awk '{print "mv " $1 " " substr($1, 1, length($1)-3) "png"}' | \
  head -5  # Проверить на первых 5
</code></pre>
<h3>Пример 6: Совмещение нескольких фильтров</h3>
<pre><code class="language-bash"># Найти топ-10 самых тяжёлых файлов
find . -type f -exec ls -lh {} \; | \
  awk '{print $5, $NF}' | \
  sort -h -r | \
  head -10

# Поток:
# find → ls → awk (фильтруем) → sort → head
</code></pre>
<h3>Пример 7: Работа с переменными окружения</h3>
<pre><code class="language-bash"># Получить список всех установленных пакетов, содержащих "mysql"
apt list --installed 2&gt;/dev/null | \
  grep "mysql" | \
  awk -F'/' '{print $1}' | \
  tee installed-mysql.txt

# tee — выводит в консоль И в файл одновременно
</code></pre>
<h3>Пример 8: Пайпы с функциями в bash</h3>
<pre><code class="language-bash"># Определить функцию для обработки
process_line() {
  echo "Обработан: $1"
}

# Использовать с пайпом
echo -e "line1\nline2\nline3" | \
  while read line; do
    process_line "$line"
  done
</code></pre>
<hr />
<h2>6. Пайпы vs xargs</h2>
<h3>Разница: stdout vs аргументы</h3>
<p dir="auto"><strong>Пайп (|)</strong> передаёт данные в stdin:</p>
<pre><code class="language-bash">echo -e "file1.txt\nfile2.txt" | cat  # cat получает текст в stdin
# Вывод:
# file1.txt
# file2.txt
</code></pre>
<p dir="auto"><strong>xargs</strong> передаёт данные как <strong>аргументы</strong> команде:</p>
<pre><code class="language-bash">echo -e "file1.txt\nfile2.txt" | xargs cat  # cat получит аргументы
# Аналогично: cat file1.txt file2.txt
</code></pre>
<h3>Когда использовать xargs?</h3>
<p dir="auto"><strong>xargs нужен когда команда НЕ читает stdin:</strong></p>
<pre><code class="language-bash"># ❌ НЕПРАВИЛЬНО: rm не читает stdin
echo "file1.txt" | rm

# ✅ ПРАВИЛЬНО: xargs преобразует stdin в аргументы
echo "file1.txt" | xargs rm

# Аналогично:
echo "file1.txt" | xargs -I {} rm {}
</code></pre>
<h3>Примеры xargs</h3>
<pre><code class="language-bash"># Удалить все временные файлы
find . -name "*.tmp" | xargs rm

# Скопировать множество файлов
ls *.jpg | xargs -I {} cp {} /backup/

# Запустить в параллель (-P 4 = 4 процесса одновременно)
cat file_list.txt | xargs -P 4 -I {} bash -c 'process_file "$1"' _ {}

# Обработать с пользовательским разделителем
find . -name "*.txt" -print0 | xargs -0 wc -l
# -print0 и -0: для файлов с пробелами в имени
</code></pre>
<h3>Сравнительная таблица</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Операция</th>
<th>Пайп</th>
<th>xargs</th>
</tr>
</thead>
<tbody>
<tr>
<td>Передача данных</td>
<td>stdin</td>
<td>аргументы</td>
</tr>
<tr>
<td>Примечание</td>
<td>“Команда читает с клавиатуры”</td>
<td>“Команда берёт от shell”</td>
</tr>
<tr>
<td>cat</td>
<td>✓</td>
<td>✓ (нужна)</td>
</tr>
<tr>
<td>grep</td>
<td>✓</td>
<td>✓ (нужна)</td>
</tr>
<tr>
<td>rm</td>
<td>✗</td>
<td>✓</td>
</tr>
<tr>
<td>cp</td>
<td>✗</td>
<td>✓</td>
</tr>
<tr>
<td>echo</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr>
<td>Параллелизм</td>
<td>✗</td>
<td>✓ (-P флаг)</td>
</tr>
</tbody>
</table>
<hr />
<h2>7. Питфоллы и решения</h2>
<h3>Проблема 1: Буферизация (данные не появляются)</h3>
<p dir="auto"><strong>Проблема:</strong> При пайпировании медленного процесса вывод задерживается.</p>
<pre><code class="language-bash"># Команда запущена, но вывода не видно 10 секунд
slow_command | grep pattern
</code></pre>
<p dir="auto"><strong>Причина:</strong> Многие программы используют full buffering при пайпировании (вместо line buffering при выводе на экран).</p>
<p dir="auto"><strong>Решение 1: stdbuf</strong></p>
<pre><code class="language-bash">slow_command | stdbuf -oL grep pattern
# -oL = line buffering для stdout
</code></pre>
<p dir="auto"><strong>Решение 2: unbuffer</strong></p>
<pre><code class="language-bash">slow_command | unbuffer grep pattern
</code></pre>
<p dir="auto"><strong>Решение 3: script/expect</strong></p>
<pre><code class="language-bash">slow_command 2&gt;&amp;1 | tee output.txt | grep pattern
# tee заставляет команду работать в line buffering режиме
</code></pre>
<h3>Проблема 2: Обработка ошибок в пайпах</h3>
<p dir="auto"><strong>Проблема:</strong> При ошибке в середине пайпа не видно, где именно.</p>
<pre><code class="language-bash">cmd1 | cmd2 | cmd3
# Если cmd2 упал, cmd3 может не выполниться корректно
</code></pre>
<p dir="auto"><strong>Решение:</strong></p>
<pre><code class="language-bash"># Проверить код возврата каждой команды
cmd1 | cmd2 | cmd3

# BASH покажет код возврата последней команды:
echo $?  # код возврата cmd3, НЕ cmd1 и cmd2!

# Правильная проверка:
set -o pipefail  # Если хоть одна упала, весь пайп упал
cmd1 | cmd2 | cmd3
echo $?  # Покажет ошибку если хоть где-то была ошибка

# Или в отдельной команде:
if cmd1 | cmd2 | cmd3; then
  echo "Успешно"
else
  echo "Ошибка в пайпе"
fi
</code></pre>
<h3>Проблема 3: Потери данных с пробелами/спецсимволами</h3>
<p dir="auto"><strong>Проблема:</strong></p>
<pre><code class="language-bash"># Файл с пробелом в имени
echo "my file.txt" | xargs rm
# ❌ Попытается удалить "my" и "file.txt" отдельно
</code></pre>
<p dir="auto"><strong>Решение:</strong></p>
<pre><code class="language-bash">echo "my file.txt" | xargs -I {} rm "{}"
# Или с print0:
find . -name "*.txt" -print0 | xargs -0 rm
</code></pre>
<h3>Проблема 4: Слишком много аргументов</h3>
<p dir="auto"><strong>Проблема:</strong></p>
<pre><code class="language-bash">ls *.txt | xargs grep "pattern"
# При 10000+ файлов: Argument list too long
</code></pre>
<p dir="auto"><strong>Решение:</strong></p>
<pre><code class="language-bash"># Ограничить количество аргументов за раз
ls *.txt | xargs -n 100 grep "pattern"

# Или более правильно:
find . -name "*.txt" -print0 | xargs -0 -n 100 grep "pattern"
</code></pre>
<h3>Проблема 5: Потеря переменных окружения</h3>
<p dir="auto"><strong>Проблема:</strong></p>
<pre><code class="language-bash">MY_VAR="hello" &amp;&amp; echo "test" | while read line; do echo $MY_VAR; done
# ❌ MY_VAR пуста! while запущен в подоболочке
</code></pre>
<p dir="auto"><strong>Решение:</strong></p>
<pre><code class="language-bash">MY_VAR="hello"
echo "test" | (
  export MY_VAR
  while read line; do echo $MY_VAR; done
)
# ✓ Работает
</code></pre>
<h3>Проблема 6: Данные из пайпа недоступны после цикла</h3>
<p dir="auto"><strong>Проблема:</strong></p>
<pre><code class="language-bash">echo -e "1\n2\n3" | while read num; do ((sum += num)); done
echo "Sum: $sum"  # ❌ sum пуст!
</code></pre>
<p dir="auto"><strong>Причина:</strong> while запущен в подоболочке, переменная не передаётся.</p>
<p dir="auto"><strong>Решение:</strong></p>
<pre><code class="language-bash">sum=0
while read num; do ((sum += num)); done &lt; &lt;(echo -e "1\n2\n3")
echo "Sum: $sum"  # ✓ 6
</code></pre>
<hr />
<h2>8. Шпаргалка</h2>
<h3>Базовый синтаксис</h3>
<pre><code class="language-bash"># Пайп
cmd1 | cmd2

# Цепочка пайпов
cmd1 | cmd2 | cmd3 | cmd4

# Редирекция stdout
cmd &gt; file
cmd &gt;&gt; file
cmd &gt; /dev/null

# Редирекция stderr
cmd 2&gt; file
cmd 2&gt;&gt; file
cmd 2&gt; /dev/null

# Объединить потоки
cmd 2&gt;&amp;1
cmd &amp;&gt; file

# Отдельные потоки
cmd 1&gt; out.txt 2&gt; err.txt

# stdin из файла
cmd &lt; file

# stdin из строки
cmd &lt;&lt;&lt; "string"

# stdin из блока
cmd &lt;&lt;EOF
line1
line2
EOF
</code></pre>
<h3>Часто используемые инструменты</h3>
<pre><code class="language-bash"># grep — фильтровать текст
cmd | grep "pattern"
cmd | grep -v "exclude"  # инверсия
cmd | grep -i "case-insensitive"

# awk — парсинг и обработка
cmd | awk '{print $2}'      # 2-е поле
cmd | awk -F: '{print $1}'  # с разделителем :
cmd | awk 'NR&gt;2'            # кроме первых 2 строк

# sed — замена текста
cmd | sed 's/old/new/'       # заменить первое
cmd | sed 's/old/new/g'      # заменить все

# sort, uniq
cmd | sort                   # отсортировать
cmd | sort -u               # уникальные
cmd | sort | uniq -c        # подсчитать

# cut — вырезать колонки
cmd | cut -d: -f1           # разделитель :, 1-е поле

# tr — трансформация символов
cmd | tr 'a-z' 'A-Z'        # в верхний регистр
cmd | tr -d '"'             # удалить кавычки

# head, tail
cmd | head -10              # первые 10 строк
cmd | tail -5               # последние 5 строк

# wc — подсчёт
cmd | wc -l                 # строк
cmd | wc -w                 # слов
cmd | wc -c                 # символов

# tee — дублировать вывод
cmd | tee file.txt          # в консоль И в файл

# xargs — передать как аргументы
cmd | xargs rm              # rm для каждого результата
cmd | xargs -n 5            # по 5 элементов за раз
cmd | xargs -P 4            # параллельно в 4 процесса
</code></pre>
<h3>Bash скелет для надёжного скрипта</h3>
<pre><code class="language-bash">#!/bin/bash
set -euo pipefail  # выход при ошибке, undefined vars, pipe ошибки

# Функция с пайпом
process_data() {
  local input_file="$1"
  
  cat "$input_file" | \
    grep "pattern" | \
    awk '{print $1}' | \
    sort | \
    uniq -c | \
    sort -rn
}

# Использование
if output=$(process_data "data.txt"); then
  echo "$output" | head -10
else
  echo "Ошибка обработки" &gt;&amp;2
  exit 1
fi
</code></pre>
<h3>Отладка пайпов</h3>
<pre><code class="language-bash"># Показать все команды перед выполнением
set -x
cmd1 | cmd2 | cmd3
set +x

# Проверить каждый этап
cmd1 &gt; /tmp/step1.txt
cat /tmp/step1.txt | cmd2 &gt; /tmp/step2.txt
cat /tmp/step2.txt | cmd3

# Или с tee:
cmd1 | tee /tmp/step1.txt | cmd2 | tee /tmp/step2.txt | cmd3

# Подробная информация
cmd 2&gt;&amp;1 | tee debug.log
less debug.log
</code></pre>
<hr />
<h2>Примеры для реальных задач</h2>
<h3>Анализ лог-файлов</h3>
<pre><code class="language-bash"># Топ ошибок за день
grep "ERROR" /var/log/app.log | \
  awk '{print $NF}' | \
  sort | uniq -c | \
  sort -rn | head -10

# Статистика по IP адресам
cat /var/log/nginx/access.log | \
  awk '{print $1}' | \
  sort | uniq -c | \
  sort -rn | head -20
</code></pre>
<h3>Управление файлами</h3>
<pre><code class="language-bash"># Найти и удалить все .tmp файлы старше 7 дней
find /tmp -name "*.tmp" -mtime +7 | xargs rm -f

# Архивировать логи старше 30 дней
find /var/log -name "*.log" -mtime +30 | \
  xargs -I {} gzip {}

# Скопировать структуру директорий
find source -type d | \
  sed 's/^source/dest/' | \
  xargs mkdir -p
</code></pre>
<h3>Обработка данных</h3>
<pre><code class="language-bash"># CSV в JSON (простой пример)
{ IFS=, read -r header; \
  while IFS=, read -r col1 col2 col3; do \
    echo "{\"col1\":\"$col1\",\"col2\":\"$col2\",\"col3\":\"$col3\"}"
  done; \
} &lt; data.csv

# Парсинг конфиг файлов
grep -v "^#" config.conf | \
  grep -v "^$" | \
  awk -F= '{gsub(/ /, "", $1); print $1 "=" $2}'
</code></pre>
<hr />
<h2>Итоги</h2>
<p dir="auto"><strong>Пайпы — это основа Unix философии:</strong></p>
<ol>
<li><strong>Простота</strong> — каждая команда делает одно</li>
<li><strong>Мощь</strong> — комбинирование создаёт сложные операции</li>
<li><strong>Эффективность</strong> — прямая передача данных через память</li>
<li><strong>Читаемость</strong> — логика цепочки видна в одной строке</li>
</ol>
<p dir="auto"><strong>Помните:</strong></p>
<ul>
<li>Пайп передаёт stdout → stdin</li>
<li>xargs передаёт данные как аргументы</li>
<li>set -o pipefail для надёжности скриптов</li>
<li>Проверяйте буферизацию при медленных процессах</li>
<li>Экранируйте спецсимволы и пробелы в файлах</li>
</ul>
]]></description><link>https://forum.exlends.ru/topic/381/bash-pajpy-polnyj-gajd-i-shpargalka</link><generator>RSS for Node</generator><lastBuildDate>Wed, 20 May 2026 07:27:17 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/381.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 30 Dec 2025 19:50:42 GMT</pubDate><ttl>60</ttl></channel></rss>