Перенаправление
Перенаправление перепрокладывает стандартные потоки до запуска команды: > усекает stdout в файл, >> добавляет в конец, < подаёт файл в stdin, 2> перехватывает stderr, а 2>&1 сливает stderr в stdout. Порядок операторов имеет значение.
Ты знаешь, что команды пишут в stdout и stderr и читают из stdin. А что, если ты хочешь сохранить вывод в файл вместо того, чтобы смотреть, как он прокручивается? Или подать содержимое файла в команду, как будто ты его напечатал? Это перенаправление — способность оболочки перепрокладывать файловые дескрипторы до того, как команда начнёт выполняться. Это одно из самых полезных действий в оболочке, а синтаксис легко запоминается, если увидеть закономерность.
К концу урока ты сможешь перенаправлять stdout и stderr в файлы, добавлять вместо перезаписи, подавать файлы в stdin и — что критически важно — понять, почему 2>&1 должен идти после >, а не перед ним.
После этого урока ты сможешь использовать > для усечения stdout в файл, >> для добавления, < для подачи файла в stdin, 2> для перехвата stderr и 2>&1 для слияния stderr в stdout. Ты понимаешь правило порядка при комбинированных перенаправлениях.
> перенаправляет stdout в файл, предварительно усекая его. Оболочка открывает целевой файл (создавая его при необходимости, усекая до нуля байт если он существует) и заменяет fd 1 этим файлом перед выполнением команды. Команда пишет как обычно — она не знает, что пишет в файл.
ls /etc > /tmp/etc-list.txtВывод на экране не появляется. /tmp/etc-list.txt теперь содержит то, что ls /etc вывел бы на экран. Если файл уже имел содержимое, > уничтожает его.
echo "first" > /tmp/demo.txt
echo "second" > /tmp/demo.txt
cat /tmp/demo.txtsecondВторой > стёр “first”. Если ты хочешь сохранить оба, нужен >>.
>> добавляет stdout в конец файла. Оболочка открывает файл в режиме добавления — существующее содержимое сохраняется, а новые данные добавляются в конец.
echo "first" > /tmp/demo.txt
echo "second" >> /tmp/demo.txt
cat /tmp/demo.txtfirst
second>> — безопасный способ накапливать вывод от нескольких команд или запусков одного скрипта.
< перенаправляет stdin из файла. Оболочка открывает файл и заменяет fd 0 им. Команда читает из fd 0 как обычно — она не знает, что байты приходят из файла, а не с клавиатуры.
wc -l < /etc/passwdwc -l считает строки. При < /etc/passwd она читает из файла вместо ожидания ввода с клавиатуры. Для большинства инструментов это эквивалентно wc -l /etc/passwd, но некоторые инструменты читают только из stdin (а не из аргумента с именем файла), делая < незаменимым.
2> перенаправляет stderr в файл. Так же, как > является сокращением для 1> (перенаправление fd 1), 2> перенаправляет fd 2.
ls /exists /nonexistent 2> /tmp/errors.txtОбычный вывод из /exists печатается в терминал. Ошибка о /nonexistent тихо уходит в /tmp/errors.txt. Ты можешь проверить ошибки позже, не загромождая экран.
Частое применение: полное отбрасывание ошибок с помощью специального нулевого устройства:
ls /nonexistent 2> /dev/null/dev/null — устройство, которое тихо отбрасывает всё, что в него записывается. Это Unix-способ сказать «подавить сообщения об ошибках».
2>&1 сливает stderr в stdout — но порядок имеет значение. Нотация N>&M означает «сделать fd N указывающим на то же место, на которое сейчас указывает fd M». Таким образом, 2>&1 означает «сделать stderr указывающим на то место, куда сейчас указывает stdout».
ls /exists /nonexistent > /tmp/all.txt 2>&1Оболочка обрабатывает перенаправления слева направо:
> /tmp/all.txt— fd 1 теперь указывает на/tmp/all.txt.2>&1— fd 2 теперь указывает на то, куда указывает fd 1, то есть на/tmp/all.txt.
Результат: и stdout, и stderr идут в файл.
Классическая ошибка — перепутать порядок:
ls /exists /nonexistent 2>&1 > /tmp/all.txtЭто неправильно. Оболочка читает слева направо:
2>&1— fd 2 устанавливается в место, куда сейчас указывает fd 1, то есть на терминал.> /tmp/all.txt— fd 1 теперь перенаправляется в файл.
Результат: stdout идёт в файл, stderr всё ещё идёт в терминал. Слияние произошло до того, как вступило в силу перенаправление в файл.
Перехватить весь вывод — stdout и stderr — в единый файл лога.
Скрипт сборки производит и обычный вывод, и сообщения об ошибках. Тебе нужно всё в одном файле для последующей проверки:
make 2>&1 | tee build.logИли без конвейера, просто в файл:
make > build.log 2>&1После запуска build.log содержит всё. Чтобы проверить только ошибки:
grep -i error build.logТеперь попробуй неправильный порядок, чтобы увидеть разницу:
make 2>&1 > build.logОшибки из make всё равно печатаются в терминал; в build.log идёт только stdout. Запоминание «сначала перенаправление stdout, затем слияние» предотвращает эту ловушку.
▸Почему это работает
На macOS/BSD все эти операторы перенаправления работают идентично — это синтаксис оболочки POSIX, а не специфика Linux. /dev/null тоже существует на macOS. Единственное отличие macOS, заслуживающее упоминания: некоторые утилиты macOS ведут себя немного иначе при аргументах с именами файлов против stdin, но сами операторы перенаправления идентичны.
▸Частая ошибка
Забыть 2>&1, когда нужен по-настоящему полный лог — единственная самая распространённая ошибка перенаправления. Команда может выглядеть успешной в логе, пока тихо выводит ошибки в терминал. Всегда проверяй: «я перехватил оба потока?» Если тебе нужно всё в одном месте: command > file 2>&1. Если нужны раздельные файлы: command > out.txt 2> err.txt.
Ты запускаешь: cmd > out.txt 2>&1. Куда идёт stderr?
Перенаправление перепрокладывает файловые дескрипторы до запуска команды. > усекает stdout в файл; >> добавляет в конец. < подаёт файл в stdin. 2> перехватывает stderr. 2>&1 копирует fd 2 для указания туда, куда сейчас указывает fd 1 — поэтому он должен идти после любого перенаправления stdout, если ты хочешь, чтобы оба потока шли в одно место. Оболочка обрабатывает все перенаправления слева направо до запуска процесса. Освой правило порядка для 2>&1 — и ты никогда больше не потеряешь вывод ошибок.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.