Pierwszeństwo przekierowania stdin i stdout w Bash

9

Moje pytanie dotyczy pierwszeństwa przekierowania to bash. Załóżmy, że masz polecenie:

cmd1 < cmd2 > cmd3

Czy to przełożyłoby się na:

(cmd1 < cmd2) > cmd3

Lub

cmd1 < (cmd2 > cmd3)

Deepak Mittal
źródło

Odpowiedzi:

11

Standard POSIX określa, że przekierowanie powłoki odbywa się od lewej do prawej; to znaczy porządek jest znaczący:

Konstrukcja 2>&1jest często używana do przekierowania standardowego błędu do tego samego pliku, co standardowe wyjście. Ponieważ przekierowania odbywają się od początku do końca, kolejność przekierowań jest znacząca. Na przykład:

ls > foo 2>&1

kieruje zarówno standardowe wyjście, jak i standardowy błąd do pliku foo. Jednak:

ls 2>&1 > foo

tylko kieruje standardowe wyjście do pliku, fooponieważ błąd standardowy został zduplikowany jako standardowe wyjście, zanim standardowe wyjście zostało skierowane do pliku foo.

bash działa zgodnie z tą częścią normy:

$ 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
$ 

Jeśli chodzi o orurowanie:

Ponieważ przypisanie potokowe standardowego wejścia lub standardowego wyjścia lub obu odbywa się przed przekierowaniem, można je zmodyfikować przez przekierowanie. Na przykład:

$ command1 2>&1 | command2

wysyła zarówno standardowe wyjście, jak i błąd command1standardowy na standardowe wejście command2.

Matt Eckert
źródło
Zakłada się, że powłoka Bash jest zgodna z POSIX.
fpmurphy
1
Nie rozumiem tego. Ponieważ powiedziałeś, że kolejność jest od lewej do prawej, nie powinno to ls > foo 2>&1oznaczać przekierowania stdout do foo, a następnie przekierowania stderr do stdout. To nie powinno działać. Podobnie drugie polecenie powinno działać. Czego tu brakuje?
Deepak Mittal
1
@ fpmurphy bashjest ogólnie zgodny z POSIX, z wyjątkiem opisanych tutaj sytuacji , w których bashzachowanie domyślne jest inne . Aby zwiększyć bashzgodność, możesz użyć tej --posixopcji.
Matt Eckert
@dpacmittal Pierwszy przykład ls > foo 2>&1działa w ten sposób: najpierw standardowe przekierowanie jest przekierowywane do foo, następnie standardowy błąd jest przekierowywany do standardowego wyjścia, którym jest teraz plik foo. Drugi przykład, ls 2>&1 > foodziała w ten sposób: błąd standardowy jest przekierowywany na standardowe wyjście przed przekierowaniem na standardowe wyjście foo, więc błąd standardowy jest generowany lokalnie, a nie kierowany do pliku.
Matt Eckert
4
@dpacmittal .. re ls 2>&1 >foo może możesz pomyśleć o tym w ten sposób. stderr z 'ls' zostaje przekierowany na stdout. To się stanie! Przejdzie do miejsca, w którym aktualnie jest przydzielone stdout , niezależnie od jakichkolwiek dalszych dyrektyw dotyczących stdout .. (ponieważ jest to jego pierwsza / pierwsza dyrektywa ). Potem pojawi się kolejna dyrektywa, która mówi, że stdout przejdzie do „foo”, i robi to ... Pamiętaj: stderr nie przekształca się w stdout. Po prostu idzie tam, gdzie stdout został przypisany w czasie obowiązywania dyrektywy. (np. terminal)
Peter.O
4

Chyba nie. Para nawiasów oznacza podpowłokę. Ale w tym przypadku żadna podpowłoka nie zostanie uruchomiona z powodu przekierowania. Bash po prostu karmi cmd2się stdin i karmi stdout cmd3.

Myślę, czy masz na myśli coś takiego cmd1 | cmd2 | cmd3? Ponieważ twoje cmd2i cmd3są zwykle normalnymi plikami zamiast „cmds”.

MetroWind
źródło