Пайпы, потоки и коды возврата

Три вещи, на которых держится всё остальное в терминале.

Три потока

У каждого процесса есть три стандартных потока:

Дескриптор Имя Назначение
0 stdin вход
1 stdout результат работы
2 stderr сообщения об ошибках

Разделение stdout и stderr — не формальность. Оно позволяет пропустить результат через пайп, а ошибки оставить на экране.

command > out.log            # только stdout
command 2> err.log           # только stderr
command > all.log 2>&1       # оба в один файл
command 2>/dev/null          # выбросить ошибки

Порядок в > all.log 2>&1 имеет значение: сначала stdout перенаправляется в файл, затем stderr — «туда же, куда stdout». Если поменять местами, stderr уйдёт на экран.

Пайпы

| соединяет stdout одной команды со stdin следующей:

ps -ef | grep nginx | wc -l

Команды работают параллельно, а не по очереди. Поэтому head на большом файле отрабатывает мгновенно: он читает первые строки и закрывает поток, а источник получает SIGPIPE и завершается.

Коды возврата

Каждая команда возвращает число: 0 — успех, всё остальное — ошибка.

grep -q pattern file
echo $?      # 0 если нашлось, 1 если нет

На этом построены условия:

command && echo "получилось"   # только при успехе
command || echo "не вышло"     # только при ошибке

Ловушка: код возврата пайпа

По умолчанию код возврата всего пайпа — это код последней команды:

false | true
echo $?      # 0 — хотя первая команда упала

В CI это приводит к зелёным сборкам при упавших тестах, если вывод тестов пропускают через что-нибудь для форматирования. Лечится опцией:

set -o pipefail
false | true
echo $?      # 1

Заголовок любого скрипта

#!/usr/bin/env bash
set -euo pipefail

Без этих трёх строк скрипт продолжает работать после сбоя, а опечатка в имени переменной превращается в пустую строку. Классический результат — rm -rf "$DIR/" при пустой DIR.

Кавычки

FILE="my file.txt"
rm $FILE        # две команды: rm my и rm file.txt
rm "$FILE"      # правильно

Правило простое: подстановку переменной всегда берут в двойные кавычки, если только вы намеренно не хотите разбиения на слова.