Пайпы, потоки и коды возврата
Три вещи, на которых держится всё остальное в терминале.
Три потока
У каждого процесса есть три стандартных потока:
| Дескриптор | Имя | Назначение |
|---|---|---|
| 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
-e— прервать выполнение при первой ошибке-u— считать ошибкой обращение к необъявленной переменной-o pipefail— учитывать ошибки внутри пайпов
Без этих трёх строк скрипт продолжает работать после сбоя, а опечатка в имени переменной превращается в пустую строку. Классический результат — rm -rf "$DIR/" при пустой DIR.
Кавычки
FILE="my file.txt"
rm $FILE # две команды: rm my и rm file.txt
rm "$FILE" # правильно
Правило простое: подстановку переменной всегда берут в двойные кавычки, если только вы намеренно не хотите разбиения на слова.