Гораздо проще визуализировать вещи, если вы думаете о том, что на самом деле происходит с «перенаправлениями» и «каналами». Перенаправления и каналы в bash делают одно: изменяют место, на которое указывают дескрипторы файлов процессов 0, 1 и 2 (см. / Proc / [pid] / fd / *).
Когда труба или "|" оператор присутствует в командной строке, первое, что должно произойти, это то, что bash создает fifo и указывает FD 1 команды левой стороны на это fifo и указывает FD 0 команды правой стороны на то же самое fifo.
Затем операторы перенаправления для каждой стороны оцениваются слева направо , и текущие настройки используются всякий раз, когда происходит дублирование дескриптора. Это важно, потому что, поскольку канал был настроен первым, FD1 (левая сторона) и FD0 (правая сторона) уже изменились по сравнению с тем, чем они обычно могли быть, и любое их дублирование будет отражать этот факт.
Поэтому, когда вы набираете что-то вроде следующего:
command 2>&1 >/dev/null | grep 'something'
Вот что происходит по порядку:
- труба (fifo) создана. «команда FD1» указывает на эту трубу. "grep FD0" также указывает на эту трубу
- «команда FD2» указывает на то место, куда в данный момент указывает «команда FD1» (канал)
- «команда FD1» указывает на / dev / null
Итак, весь вывод, который «команда» записывает в свой FD 2 (stderr), попадает в канал и читается «grep» с другой стороны. Все выходные данные, которые «команда» записывает в свой FD 1 (стандартный вывод), попадают в / dev / null.
Если вместо этого вы запустите следующее:
command >/dev/null 2>&1 | grep 'something'
Вот что происходит:
- создается канал, и на него указывают "команда FD 1" и "grep FD 0"
- "команда FD 1" указывает на / dev / null
- «команда FD 2» указывает на то, куда в данный момент указывает FD 1 (/ dev / null)
Итак, все stdout и stderr из «команды» переходят в / dev / null. Ничто не идет к трубе, и, таким образом, "grep" будет закрываться, ничего не отображая на экране.
Также обратите внимание, что перенаправления (файловые дескрипторы) могут быть только для чтения (<), только для записи (>) или для чтения-записи (<>).
Последнее замечание. Записывает ли программа что-то в FD1 или FD2, полностью зависит от программиста. Хорошая практика программирования гласит, что сообщения об ошибках должны идти в FD 2, а нормальный вывод - в FD 1, но вы часто найдете неаккуратное программирование, которое смешивает два или иным образом игнорирует соглашение.