Masz już kilka bardzo dobrych odpowiedzi. Chciałbym jednak podkreślić, że w grę wchodzą dwie różne koncepcje, których zrozumienie ogromnie pomaga:
Tło: deskryptor pliku a tabela plików
Twój deskryptor pliku to tylko liczba 0 ... n, która jest indeksem w tabeli deskryptorów plików w twoim procesie. Zgodnie z konwencją STDIN = 0, STDOUT = 1, STDERR = 2 (zwróć uwagę, że STDIN
tutaj terminy itp. Są tylko symbolami / makrami używanymi w konwencji w niektórych językach programowania i stronach podręcznika , nie ma rzeczywistego „obiektu” o nazwie STDIN; dla celem tej dyskusji, STDIN jest 0 itd.).
Ta tabela deskryptorów plików sama w sobie nie zawiera żadnych informacji na temat rzeczywistego pliku. Zamiast tego zawiera wskaźnik do innej tabeli plików; ten ostatni zawiera informacje o rzeczywistym pliku fizycznym (lub urządzeniu blokowym, potoku lub czymkolwiek innym, co Linux może rozwiązać za pomocą mechanizmu plików) i więcej informacji (tj. czy to do odczytu, czy zapisu).
Więc kiedy używasz >
lub <
w swojej powłoce, po prostu zastępujesz wskaźnik odpowiedniego deskryptora pliku, aby wskazać coś innego. Składnia 2>&1
po prostu wskazuje deskryptor 2 na dowolne 1 punkty. > file.txt
po prostu otwiera się file.txt
do pisania i pozwala STDOUT (plik decsriptor 1) wskazywać na to.
Istnieją inne zalety, np. 2>(xxx)
( Np . : stwórz nowy proces xxx
, stwórz potok, podłącz deskryptor pliku 0 nowego procesu do końca odczytu potoku i podłącz deskryptor pliku 2 oryginalnego procesu do końca zapisu rura).
Jest to również podstawa dla „magii obsługi plików” w innym oprogramowaniu niż twoja powłoka. Na przykład możesz w swoim skrypcie Perl dup
powiązać deskryptor pliku STDOUT z innym (tymczasowym), a następnie ponownie otworzyć STDOUT dla nowo utworzonego pliku tymczasowego. Od tego momentu wszystkie dane wyjściowe STDOUT z własnego skryptu Perla i wszystkie system()
wywołania tego skryptu znajdą się w tym pliku tymczasowym. Po dup
zakończeniu możesz przywrócić STDOUT do tymczasowego deskryptora, w którym go zapisałeś, i presto, wszystko jest jak poprzednio. W międzyczasie możesz nawet pisać do tego tymczasowego deskryptora, więc podczas gdy twoje rzeczywiste wyjście STDOUT trafia do pliku tymczasowego, nadal możesz faktycznie wypisywać rzeczy do prawdziwego STDOUT (zwykle użytkownika).
Odpowiedź
Aby zastosować podane powyżej informacje podstawowe do pytania:
W jakiej kolejności powłoka wykonuje polecenia i przekierowuje strumień?
Z lewej na prawą.
<command> > file.txt 2>&1
fork
od nowego procesu.
- Otwórz
file.txt
i zapisz jego wskaźnik w deskryptorze pliku 1 (STDOUT).
- Wskaż STDERR (deskryptor pliku 2) na cokolwiek, na co wskazuje teraz fd 1 (co znowu jest już
file.txt
oczywiście otwarte ).
exec
<command>
To najwyraźniej przekierowuje najpierw stderr na stdout, a następnie wynikowy stdout jest przekierowywany do pliku.txt.
Miałoby to sens, gdyby istniał tylko jeden stół, ale jak wyjaśniono powyżej, są dwa. Deskryptory plików nie wskazują na siebie rekurencyjnie, nie ma sensu myśleć „przekieruj STDERR do STDOUT”. Prawidłowa myśl to „wskaż STDERR tam, gdzie wskazuje STDOUT”. Jeśli zmienisz STDOUT później, STDERR pozostanie tam, gdzie jest, nie magicznie idzie w parze z kolejnymi zmianami w STDOUT.