Różnica między 2> i 1> output.log a 2> i 1 | tee output.log


35

Chciałem poznać różnicę między następującymi dwoma poleceniami

2>&1 > output.log 

i

2>&1 | tee output.log

Widziałem, jak jeden z moich kolegów używa drugiej opcji przekierowania. Wiem, co robi 2> i 1, moje jedyne pytanie brzmi: jaki jest cel używania tee, w którym można użyć prostego przekierowania „>”?

Odpowiedzi:


11

Patrząc na dwa polecenia osobno:

utility 2>&1 >output.log 

Ponieważ przekierowania są przetwarzane od lewej do prawej, standardowy strumień błędów byłby najpierw przekierowywany do dowolnego miejsca, w którym idzie standardowy strumień wyjściowy (ewentualnie do konsoli), a następnie standardowy strumień wyjściowy byłby przekierowywany do pliku. Standardowy strumień błędów nie zostałby przekierowany do tego pliku.

Widocznym efektem tego jest to, że otrzymujesz to, co jest generowane przy standardowym błędzie na ekranie, i to, co jest wytwarzane przy standardowym wyjściu w pliku.

utility 2>&1 | tee output.log

Tutaj przekierowujesz standardowy błąd w to samo miejsce, co standardowy strumień wyjściowy. Oznacza to, że oba strumienie będą przesyłane do teenarzędzia jako pojedynczy, przeplatany strumień wyjściowy, i że te standardowe dane wyjściowe zostaną zapisane w danym pliku przez tee. Dane byłyby dodatkowo odtwarzane przez teekonsolę (w ten teesposób duplikuje strumienie danych).

To, które z nich zostanie użyte, zależy od tego, co chcesz osiągnąć.

Zauważ, że nie byłbyś w stanie odtworzyć efektu drugiego potoku tylko za pomocą >(jak w utility >output.log 2>&1, co zapisałoby zarówno standardowe wyjście, jak i błąd w pliku). Musisz użyć, teeaby uzyskać dane w konsoli, a także w pliku wyjściowym.


Dodatkowe uwagi:

The Widoczny efekt pierwszego polecenia

utility 2>&1 >output.log 

byłby taki sam jak

utility >output.log

To znaczy, standardowe wyjście trafia do pliku, a standardowy błąd trafia do konsoli.

Gdyby na końcu każdego z powyższych poleceń dodano kolejny krok przetwarzania, istniałaby duża różnica:

utility 2>&1 >output.log | more_stuff

utility >output.log      | more_stuff

W pierwszym potoku more_stuffuzyskałby to, co pierwotnie jest standardowym strumieniem błędów, utilityjako swoje standardowe dane wejściowe, natomiast w drugim potoku, ponieważ jest to tylko wynikowy standardowy strumień wyjściowy, który jest kiedykolwiek wysyłany przez potok, more_stuffczęść potoku nie otrzyma nic czytać na jego standardowym wejściu.


Za pomocą polecenia „ utility 2>&1 | tee output.logmasz na myśli, że ponieważ 1 jest kierowane do tee, również 2. 2. Ponieważ tee duplikuje strumień, dane wyjściowe są wyświetlane zarówno na konsoli, jak i zapisywane do pliku? Stąd różnica między utility 2>&1 > output.logi utility 2>&1 | tee output.logpolega teena tym, że powiela strumień. Czy to prawda?
Zmotywowano

Z przykładami utility 2>&1 > output.log | more_stuffi utility >ouput.log| more_stuff , is the difference that more_stuff` ma standardowe wyjście błędów do konsoli jako dane wejściowe more_stuff? Ponieważ w drugim przykładzie konsola nie ma danych wyjściowych, zasadniczo nie ma danych wejściowych do more_stuff? Jeśli tak, nie jest to jasne, ponieważ w poprzednim akapicie zauważasz, że standardowe wyjście trafia do pliku, a standardowy błąd do konsoli.
Zmotywowany

@Motivated Twój pierwszy komentarz wydaje mi się poprawny, tak. Co do drugiego komentarza: w pierwszym poleceniu more_stuffotrzyma to, co utilitypierwotnie wysłano do jego strumienia błędów (ale które zostało przekierowane na standardowe wyjście). Nie dlatego, że trafiłby na konsolę, gdyby more_stuffgo nie było, ale dlatego, że przechodzi do standardowego strumienia wyjściowego . W drugim poleceniu nic niemore_stuff otrzymuje, ponieważ nie ma standardowego wyjścia z lewej strony potoku. Strumień błędów z nadal trafiałby do konsoli w drugim poleceniu. utility
Kusalananda

Dzięki. Czy masz na myśli to, że ponieważ polecenie utility > output.log | more_stuffnie powoduje wyjścia w standardowym strumieniu wyjściowym ze standardowego punktu widzenia błędu?
Zmotywowany

@Motivated Ponieważ lewa strona nie wytwarza niczego na standardowym wyjściu (jest przekierowywana), żadne dane nie będą przesyłane przez potok.
Kusalananda

24

Nota redakcyjna

Przeczytaj komentarze do tej odpowiedzi - derobert .


Oryginalna odpowiedź

2>&1 >output.logoznacza, że ​​najpierw zacznij wysyłać wszystkie uchwyty pliku 2 (błąd standardowy) do uchwytu pliku 1 (standardowe wyjście), a następnie wyślij je do pliku output.log. Innymi słowy, wyślij standardowy błąd i standardowe wyjście do pliku dziennika.

2>&1 | tee output.logjest taki sam z 2>&1bitem, łączy standardowe wyjście i standardowy błąd ze standardowym strumieniem wyjściowym. Następnie przepuszcza to przez teeprogram, który wyśle ​​standardowe wejście na standardowe wyjście (jak cat), a także do pliku. Łączy więc dwa strumienie (błąd i dane wyjściowe), a następnie przekazuje je do terminala i pliku.

Najważniejsze jest to, że pierwszy wysyła stderr/ stdoutdo pliku, podczas gdy drugi wysyła go zarówno do pliku, jak i do standardowego wyjścia (co jest prawdopodobnie to terminal, chyba że znajdujesz się w innej konstrukcji, która przekierowała standardowe wyjście).

Wspominam o tej ostatniej możliwości, ponieważ możesz mieć takie rzeczy jak:

(echo hello | tee xyzzy.txt) >plugh.txt

gdzie nic nie kończy się na terminalu.


13
-1 Masz poprawną składnię, ale nie semantykę. Uruchom cat /doesnotexist 2>&1 >output.txt- zobaczysz cat: /doesnotexist: No such file or directorywyświetlane na terminalu, a output.txt jest pustym plikiem. 2>&1Stosowana jest kolejność pierwszeństwa i zamykania: (dup fd2 z bieżącego fd1), a następnie >output.txt(przekieruj fd1 do output.txt, nie zmieniając niczego innego). Innym powodem 2>&1 |jest kolejność pierwszeństwa: |wcześniej >.
Arcege,

5
Ta odpowiedź jest zasadniczo błędna w zasadzie pod każdym względem . Wiele z poniższych odpowiedzi jest lepszych, ale myślę, że ta autorstwa Kusalanandy jest najbardziej przejrzysta.
Michael Homer

2
@ user14408: Jeśli kiedykolwiek utworzysz konto w systemie Unix i Linux i uzyskasz tę odpowiedź, usuń moją notatkę redakcyjną po tym, jak skomentujesz komentarze.
derobert

8

Pierwsze polecenie wykona inne zadanie:

Po

2>&1 > output.log 

stary STDOUT zostanie zapisany (skopiowany) w STDERR, a następnie STDOUT zostanie przekierowany do pliku.

Stdout przejdzie do pliku, a stderr przejdzie do konsoli.

I w

 2>&1 | tee output.log

oba strumienie zostaną przekierowane do tee. Tee zduplikuje wszelkie dane wejściowe na standardowe wyjście (konsola w twoim przypadku) i do pliku (output.log ).

I jest jeszcze jedna forma pierwszego:

    > output.log  2>&1

spowoduje to przekierowanie zarówno STDOUT, jak i STDERR do pliku.


4

Te pierwsze generują tylko plik. Drugi wyświetla zarówno plik, jak i ekran.


4

Powodem 2>&1 | teejest możliwość przechwycenia zarówno stdout, jak i stderr do pliku dziennika i jednoczesnego wyświetlenia go na ekranie. Można to również zrobić >output.txt 2>&1 & tail -f, ale nie wiadomo, kiedy zakończyła się komenda w tle - czy program został zakończony, czy działa bez wyjścia. To 2>&1 | teebył wspólny idiom dla programistów.


Czy chcesz powiedzieć, że na przykład 2> & 1> plik.txt nie przechwyciłby zarówno stdout, jak i stderr do file.txt?
Zmotywowany

0

Najpierw zobaczmy przykładowy kod:

#include <stdio.h>
main() 
{
// message 1, on stdout (using  printf)
printf("%s",          "message 1, on stdout (using  printf)\n");

// message 2, on stdout (using fprintf)
fprintf(stdout, "%s", "message 2, on stdout (using fprintf)\n");

// message 3, on stderr (using fprintf)
fprintf(stderr, "%s", "message 3, on stderr (using fprintf)\n");
}

Porównajmy wyniki:
./helloerror
+ plik: brak wiadomości; konsola: komunikat 1,2,3;

./helloerror >error.txt
+ plik: wiadomość 1,2; konsola: komunikat 3;

./helloerror 2>&1 >error.txt
+ plik: wiadomość 1,2; konsola: komunikat 3;
+ to samo co ./helloerror> error.txt

./helloerror >error.txt 2>&1
+ plik: komunikat 3,1,2; konsola: brak wiadomości;
+ zwróć uwagę, że kolejność 3 jest pierwsza, potem 1, a następnie 2

./helloerror | tee error.txt 2>&1
+ plik: wiadomość 1,2; konsola: komunikat 3,1,2;
+ zwróć uwagę, że kolejność 3 jest pierwsza, potem 1, a następnie 2

./helloerror 2>&1 | tee error.txt
+ plik: komunikat 3,1,2; konsola: komunikat 3,1,2;

Aby użyć:
./helloerror >error.txt 2>&1
-> jeśli chce się wszystkich (stdout + stderr) wiadomości w pliku, ale nie jest zapisanych na konsoli

./helloerror 2>&1 | tee error.txt
-> jeśli ktoś chce wszystkie (stdout + stderr) wiadomości w pliku i drukowane na konsoli


-1

Oto post podsumowujący strumienie wyjściowe systemu Unix: http://www.devcodenote.com/2015/04/unix-output-streams.html

Fragment posta:

Istnieją 3 standardowe strumienie wyjściowe:

STDIN - Standard Input - Writes from an input device to the program
STDOUT - Standard Output - Writes program output to screen unless specified otherwise.
STDERR - Standard Error Output - Writes error messages. Also printed to the screen unless specified otherwise.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.