Три потока: stdin, stdout, stderr
Понимаем, откуда программа берёт ввод и куда отправляет вывод и ошибки.
Стандартные потоки — это три канала, которые есть у любой программы: ввод (stdin), вывод (stdout) и ошибки (stderr).
Зачем разделять вывод и ошибки
Каждая программа в Unix по умолчанию получает три открытых потока с номерами-дескрипторами: 0 — stdin (откуда читать), 1 — stdout (куда писать результат), 2 — stderr (куда писать ошибки). Разделение нужно, чтобы можно было отдельно собрать результат и отдельно — диагностику.
┌──────────────┐
stdin 0 ──▶│ программа │──▶ stdout 1 (результат)
└──────────────┘──▶ stderr 2 (ошибки)Поток ошибок отдельно от результата
Рассмотрим команду, которая что-то находит, а что-то нет:
ls /etc /not-existВывод:
ls: cannot access '/not-exist': No such file or directory /etc: hosts passwd
Здесь строка с ошибкой ушла в stderr (поток 2), а список файлов — в stdout (поток 1). На экране они смешаны, но это разные каналы, и их можно развести.
Перенаправление потока ошибок
Чтобы отправить только ошибки в файл, перенаправляют дескриптор 2:
ls /etc /not-exist 2> errors.log
cat errors.logВывод:
ls: cannot access '/not-exist': No such file or directory
Запись 2> значит «перенаправить поток 2 (stderr)». В файл попали только ошибки, а нормальный вывод остался на экране. Чтобы выбросить ошибки совсем, направляют их в «чёрную дыру»: 2> /dev/null.
Как работает под капотом
Дескриптор — это просто целое число, индекс в таблице открытых файлов процесса. По умолчанию все три указывают на терминал, поэтому вы видите и вывод, и ошибки в одном окне. Когда вы пишете 2> file, Bash до запуска программы подменяет дескриптор 2 на этот файл. Сама программа не знает, куда реально идёт поток — она просто пишет в номер 2.
Частые ошибки
- Ждать, что ошибки попадут в файл при обычном >.
cmd > out.txtловит только stdout; ошибки всё равно вылезут на экран. - Пробел между 2 и >. Нужно
2>слитно;2 >Bash поймёт иначе. - Считать /dev/null файлом с данными. Это устройство-«пустота»: всё записанное туда исчезает, чтение даёт пусто.
Итог
- У программы три потока: stdin (0), stdout (1), stderr (2).
- Результат идёт в stdout, ошибки — в stderr; их можно разделять.
2> fileперенаправляет ошибки,2> /dev/nullих выбрасывает.