Intereting Posts

Операторы перенаправления всегда открывают дескрипторы файлов параллельно?

1. Рассмотрим фрагмент # 1:

$ cat test.txt > test.txt cat: test.txt: input file is output file 

Кажется, что cat делает свой дескриптор входного файла в test.txt, а затем, когда он пытается установить дескриптор выходного файла в test.txt, он выдает указанную выше ошибку. Здесь кажется, что cat известно о переадресации оператора, и поэтому продолжает пытаться установить дескриптор выходного файла на test.txt

2. Рассмотрим фрагмент № 2:

 $ cat 1.txt 1:CAT 2:dog $ sed 's/cat/CAT/g' test.txt 1:CAT 2:dog $ sed 's/cat/CAT/g' test.txt > test.txt $ cat test.txt # Note that test.txt is now empty $ 

Здесь мы видим, что sed открывает test.txt (последний аргумент) в режиме чтения и в то же время устанавливает test.txt качестве дескриптора вывода файла. Кроме того '>' оператор '>' перезаписывает содержимое файла, перед началом которого начинает считываться sed .

Я знаю, что команды в конвейере выполняются параллельно, но не имеют никакой информации о том, как ведут себя операторы перенаправления. Любые поддерживающие ссылки были бы полезны.

В дополнение к документации, на которую указывает Jordanm, я хочу, чтобы вы исправили неверное представление, проиллюстрированное в вашем вопросе, – выполненная программа не обрабатывает перенаправления. Он почти не знает о них. Оболочка обрабатывает перенаправления.

Программа запускается с тремя открытыми файлами: stdin (# 0), stdout (# 1) и stderr (# 2). Если вы просто запустите программу из командной строки, они будут подключены к вашему терминальному устройству, поэтому программа считывает то, что вы набираете (stdin), и печатает выходные данные (stdout) и ошибки (stderr) на свой терминал.

В качестве примера я просто запускаю cat в терминале (который говорит tty : /dev/pts/31 ). Я могу проверить, какие файлы он открыл с помощью lsof :

 $ lsof -a -p `pidof cat` -d0,1,2 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME cat 21257 anthony 0u CHR 136,31 0t0 34 /dev/pts/31 cat 21257 anthony 1u CHR 136,31 0t0 34 /dev/pts/31 cat 21257 anthony 2u CHR 136,31 0t0 34 /dev/pts/31 

Действительно, мы видим, что терминал открыт для всех трех. Теперь вместо этого давайте попробуем довольно глупый вызов cat: cat < /dev/zero > /dev/null 2>/dev/full , который перенаправляет все три:

 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME cat 21838 anthony 0r CHR 1,5 0t0 1030 /dev/zero cat 21838 anthony 1w CHR 1,3 0t0 1028 /dev/null cat 21838 anthony 2w CHR 1,7 0t0 1031 /dev/full 

Оболочка реализовала эти перенаправления, передав три устройства как stdin, stdout и stderr (вместо терминала). Корпус аналогично реализует трубы. Попробуем cat | dd > /dev/null cat | dd > /dev/null (довольно глупая труба, действительно):

 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME cat 22507 anthony 0u CHR 136,31 0t0 34 /dev/pts/31 cat 22507 anthony 1w FIFO 0,8 0t0 56081395 pipe cat 22507 anthony 2u CHR 136,31 0t0 34 /dev/pts/31 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME dd 22508 anthony 0r FIFO 0,8 0t0 56081395 pipe dd 22508 anthony 1u CHR 136,31 0t0 34 /dev/null dd 22508 anthony 2u CHR 136,31 0t0 34 /dev/pts/31 

Обратите внимание, как оболочка открыла трубу, и она использовала ее для соединения stdout cat с stdin dd . И далее, как он связал stdout dd с /dev/null .

Выполняемые команды не знают о перенаправлениях. Они просто используют stdin, stdout, stderr как обычно. Все они могут быть терминалом, или они могут быть перенаправлены в / из файла, устройства или, возможно, в другую программу. Или даже сетевой сокет, если ваша оболочка поддерживает это.

Даже самые смехотворно сложные конвейеры на самом деле являются лишь инструкциями для оболочки о том, как связать эти три дескриптора файлов перед выполнением программы.

(ПРИМЕЧАНИЕ. Некоторые программы ведут себя по-разному в случае, когда один из них подключен к терминалу, но обычно это более удобно для интерактивного использования. Например, ls переключается на вывод с одним столбцом и без цвета, когда stdout не является терминал, который обычно вам нужен, если вы собираетесь передать его в другую программу. Некоторые программы обрабатывают запрос по-другому, если stdin не является терминалом. И так далее.)

Перенаправление происходит сначала в оболочке. В вашем примере:

 cat test.txt > test.txt 

Первое, что происходит, – bash, открывает test.txt , который обрезает файл. Теперь он пуст, прежде чем cat будет test.txt с test.txt в качестве аргумента.

Из раздела перенаправления справочной страницы bash:

Перед выполнением команды его ввод и вывод могут быть перенаправлены с использованием специальной нотации, интерпретируемой оболочкой. Перенаправление также может использоваться для открытия и закрытия файлов для текущей среды выполнения оболочки. Следующие операторы перенаправления могут предшествовать или появляться в любой точке простой команды или могут следовать за командой. Перенаправления обрабатываются в том порядке, в котором они появляются, слева направо.

Я не вижу ничего в спецификации POSIX, чтобы указать, что это должно произойти первым, но я не знаю о оболочке, где это не так.