Приоритет перенаправления stdin и stdout в Bash

9

Мой вопрос о приоритете перенаправления bash. Предположим, у вас есть команда:

cmd1 < cmd2 > cmd3

Будет ли это переводить на:

(cmd1 < cmd2) > cmd3

Или

cmd1 < (cmd2 > cmd3)

Дипак Миттал
источник

Ответы:

11

Стандарт POSIX указывает, что перенаправление оболочки происходит слева направо; порядок значим:

Конструкция 2>&1часто используется для перенаправления стандартной ошибки в тот же файл, что и стандартный вывод. Поскольку перенаправления происходят от начала до конца, порядок перенаправлений является значительным. Например:

ls > foo 2>&1

направляет как стандартный вывод, так и стандартную ошибку в файл foo. Однако:

ls 2>&1 > foo

только стандартный вывод направляет в файл, fooпотому что стандартная ошибка была продублирована как стандартный вывод до того, как стандартный вывод был направлен в файл foo.

bash работает в соответствии с этой частью стандарта:

$ ls doesnotexist > foo 2>&1
$ cat foo
ls: cannot access doesnotexist: No such file or directory
$ ls doesnotexist 2>&1 > foo
ls: cannot access doesnotexist: No such file or directory
$ cat foo
$ 

Что касается трубопровода:

Поскольку конвейерное присвоение стандартного ввода или стандартного вывода или того и другого происходит перед перенаправлением, его можно изменить перенаправлением. Например:

$ command1 2>&1 | command2

отправляет как стандартный вывод, так и стандартную ошибку command1на стандартный ввод command2.

Мэтт Экерт
источник
Это предполагает, что оболочка Bash совместима с POSIX.
fpmurphy
1
Я не понимаю этого. Так как вы сказали, что порядок слева направо, это не ls > foo 2>&1означает перенаправление stdout в foo, а затем перенаправление stderr в stdout. Так что это не должно работать. Аналогично вторая команда должна работать. Что мне здесь не хватает?
Дипак Миттал
1
@fpmurphy, bashкак правило, соответствует POSIX, за исключением случаев, описанных здесь , где bashповедение по умолчанию отличается. Чтобы сделать bashсоответствие больше, вы можете использовать --posixопцию.
Мэтт Экерт
@dpacmittal Первый пример, ls > foo 2>&1работает следующим образом: сначала стандартный вывод перенаправляется на foo, затем стандартная ошибка перенаправляется на стандартный вывод, который теперь является файлом foo. Второй пример, ls 2>&1 > fooработает следующим образом: стандартная ошибка перенаправляется на стандартный вывод перед перенаправлением на стандартный вывод foo, поэтому стандартная ошибка отображается локально, а не направляется в файл.
Мэтт Экерт
4
@dpacmittal .. re, ls 2>&1 >foo может быть, вы можете думать об этом, как это. stderr из 'ls' перенаправляется в stdout. Это случится! Он пойдет туда, куда в настоящее время назначен stdout , независимо от каких-либо дальнейших директив, касающихся stdout .. (потому что это его первичная / первая директива ) .. Затем приходит еще одна директива, которая говорит, что stdout перейдет в "foo", и это делает ... Помните: stderr не превращается в фактическое превращение в стандартный вывод. Он просто идет туда, где был назначен стандартный вывод во время директивы. (например, терминал)
Peter.O
4

Я думаю, что нет. Пара круглых скобок означает под-оболочку. Но в этом случае суб-оболочка не будет запущена из-за перенаправления. Bash просто вводит cmd2в stdin и вводит stdout в cmd3.

Я думаю, ты имеешь в виду что-то подобное cmd1 | cmd2 | cmd3? Потому что ваши cmd2и cmd3обычно нормальные файлы вместо "cmds".

MetroWind
источник