Pytanie W powłoce, co oznacza "2> i 1"?


W powłoce Uniksa, jeśli chcę się połączyć stderr i stdout do stdout strumień do dalszej manipulacji, mogę dodać następujące na końcu mojego polecenia:

2>&1

Tak więc, jeśli chcę użyć head na wyjściu z g++Mogę zrobić coś takiego:

g++ lots_of_errors 2>&1 | head

więc widzę tylko kilka pierwszych błędów.

Zawsze mam kłopoty z zapamiętywaniem tego, i ciągle muszę je sprawdzać, i to głównie dlatego, że nie w pełni rozumiem składnię tej konkretnej sztuczki.

Czy ktoś może to przełamać i wyjaśnić charakter przez bohatera, co 2>&1  znaczy?


1738
2018-05-03 22:57


pochodzenie


@dbr Nie sądzę, że to po prostu bash - wierzę, że to rzecz bourne shell; stąd sh, bash, ksh, ash, dash itd. - guns
Jest to część paragrafu przekierowania opisującego powłoki zgodne z POSIX lub POSIX-a dla skrótu. ksh jest na przykład powłoką POSIX. Widzieć:pubs.opengroup.org/onlinepubs/009695399/utilities/... - jim mcnamara
Ta konstrukcja działa również w systemie Windows. - Vadzim
Zasadniczo lepiej to robić 2>&1 niż 2> / dev / null ;-) - F. Hauri
Myślałem, że o tym wspomnę |&  jest skrótem dla 2>&1 | jeśli używasz Zsh. Nie mogę się odezwać, czy dotyczy to innych skorup podobnych do burty, czy też jest to tylko funkcja zsh. - chrixian


Odpowiedzi:


Deskryptor pliku 1 jest standardowym wyjściem (stdout).
Deskryptor pliku 2 jest błędem standardowym (stderr).

Oto jeden ze sposobów zapamiętywania tego konstruktu (chociaż nie jest on całkowicie dokładny): na początku 2>1 może wyglądać na dobry sposób przekierowania stderr do stdout. Będzie to jednak interpretowane jako "przekierowanie stderr do pliku o nazwie 1". & wskazuje, że to, co następuje, to deskryptor pliku, a nie nazwa pliku. Tak więc konstrukcja staje się: 2>&1.


1943
2018-05-03 23:04



ale raczej nie powinno tak być &2>&1? - dokaspar
@Dominik: Nie, & interpretowane jest jako "deskryptor pliku" w kontekście przekierowań. Pisanie command &2>& jest parsowany jako command & i 2>&1, tj. "uruchom command w tle, a następnie uruchom polecenie 2 i przekieruj jego standardowe wyjście do standardowego wyjścia ". - Adam Rosenfield
Interesujące informacje tutaj: mywiki.wooledge.org/BashFAQ/055 - Halil Özgür
Ale w jaki sposób przekierowałbyś stderr do pliku o nazwie "& 1"? - Martín Fixman
@Jaskółka oknówka: 2>'&1' - rogual


echo test > afile.txt

przekierowuje standardowe wyjście do afile.txt. To jest to samo co robienie

echo test 1> afile.txt

Aby przekierować stderr, wykonaj następujące czynności:

echo test 2> afile.txt

>& to składnia przekierowująca strumień do innego deskryptora pliku - 0 to stdin, 1 to stdout, a 2 to stderr.

Możesz przekierować standardowe wyjście do stderr, wykonując:

echo test 1>&2 # or echo test >&2

Lub odwrotnie:

echo test 2>&1

Krótko mówiąc ... 2> przekierowuje stderr do (nieokreślonego) pliku, dołączając &1 przekierowuje stderr na stdout.


481
2018-05-03 22:59



Czy to ma dla ciebie jakiś sens, java ... 2&1 >> data.log, Widziałem, jak to zrobił jeden z moich kolegów? - Thang Pham
@Harry, który wygląda jak powłoka, która nie jest bash lub literówka .. cmd 2>&1 >> somefile.log doda plik stdout / stderr do pliku - w zasadzie jest taki sam jak powyżej, z >> file dołączyć - dbr
@dbr cmd 2>&1 >>file nie przekierowuje stderr do pliku, ale cmd >> file 2>&1 robi. Zamów sprawy. W pierwszym przypadku stderr jest przekierowywany na stdout powłoki (prawdopodobnie tty, jeśli polecenie jest wprowadzane interaktywnie), a następnie stdout jest kierowany do pliku. W drugim przypadku stdout jest kierowany do pliku, a stderr jest kierowany do tego samego miejsca. - William Pursell
Podoba mi się powyższa odpowiedź, ale może to być wyraźniejszy akcent. "2> i 1" przekierowuje stderr na cel stdout. Więc jeśli masz coś w rodzaju "ls -l >> directoryContents 2> & 1" Wynik będzie plikiem o nazwie directoryContents będzie zawierał zawartość katalogu roboczego dołączonego do niego. Jeśli wystąpią jakiekolwiek błędy w wykonywaniu: komunikaty o błędach będą również dołączane do pliku directoryContents, gdy się pojawią. - Max West
Jest 0(or 1,2)>&0(or 1,2) jak opcja kontroli wyjścia? Jest echo test >test.log 2>&1 taki sam jak echo test 2>&1 >test.log? - Simin Jie


Kilka sztuczek dotyczących przekierowania

Pewna składnia w tym zakresie może mieć ważne zachowania. Jest trochę małych próbek o przekierowaniach, STDERR, STDOUTi argumenty zamawianie.

1 - Nadpisywanie lub dołączanie?

Symbol > oznaczać przekierowanie.

  • > oznaczać wysłać jako kompletny plik, nadpisywanie celu, jeśli istnieje (patrz noclobber Funkcja bash w # 3 później).
  • >> oznaczać wyślij dodatkowo dołączy się do celu, jeśli istnieje.

W każdym razie plik zostanie utworzony, jeśli nie istnieje.

2 - The wiersza poleceń powłoki zależy od zamówienia !!

Do testowania tego potrzebujemy proste polecenie, które wyśle ​​coś na obu wyjściach:

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(Oczekiwany, że nie masz nazwanego katalogu /tnt, oczywiście ;). Cóż, mamy to !!

Zobaczmy więc:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

Ostatnia zrzutu linii poleceń STDERR na konsolę i wydaje się, że nie jest to oczekiwane zachowanie ... Ale ...

Jeśli chcesz zrobić po filtrowaniu około jednego wyjścia, drugiego lub obu:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

Zauważ, że ostatni wiersz polecenia w tym akapicie jest dokładnie taki sam jak w poprzednim akapicie, gdzie napisałem wydaje się nie być oczekiwanym zachowaniem (więc może to być nawet oczekiwane zachowanie).

Cóż, istnieje kilka sztuczek dotyczących przekierowań, dla robi różne operacje na obu wyjściach:

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

Nota: &9deskryptor wystąpiłby spontanicznie z powodu ) 9>&2.

Dodatek: nota! Z nową wersją  (>4.0) jest nowa funkcja i bardziej seksowna składnia do robienia tego typu rzeczy:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

I wreszcie dla takiego kaskadowego formatowania wyjściowego:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Dodatek: nota! Ta sama nowa składnia w obu przypadkach:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Gdzie STDOUT przejść przez konkretny filtr, STDERR do drugiego i ostatecznie oba wyjścia połączone przechodzą przez trzeci filtr poleceń.

3 - Słowo o noclobber opcja i >| składnia

O to chodzi nadpisywanie:

Podczas set -o noclobber poinstruuj bash na nie zastąpić istniejący plik, >| Składnia pozwala ci przejść przez to ograniczenie:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

Plik jest nadpisywany za każdym razem, cóż teraz:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

Przejdź przez >|:

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

Odzbrojenie tej opcji i / lub zapytanie, jeśli jest już ustawione.

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - Ostatnia sztuczka i więcej ...

Do przekierowania obie wyjście z danego polecenia, widzimy, że prawidłowa składnia może być:

$ ls -ld /tmp /tnt >/dev/null 2>&1

dla tego specjalny W przypadku, istnieje skrócona składnia: &> ... lub >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

Nota: jeśli 2>&1 istnieć, 1>&2 jest również poprawna składnia:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b- Teraz pozwolę ci pomyśleć o:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c - Jeśli jesteś zainteresowany jeszcze Informacja

Możesz przeczytać dokładną instrukcję, uderzając:

man -Len -Pless\ +/^REDIRECTION bash

w  konsola ;-)


257
2018-04-29 16:33



Dalsze czytanie: Jeśli ci się to spodobało, możesz odetchnąć: Jak nadużywanie przekierowań może dawać dziwne zachowania - F. Hauri
Dalsze czytanie ||: A funkcja do przechowywania obu wyników w oddzielnych zmiennych - F. Hauri


Liczby odnoszą się do deskryptorów plików (fd).

  • Zero jest stdin 
  • Jeden jest stdout 
  • Dwa to stderr

2>&1 przekierowuje fd 2 na 1.

Działa to dla dowolnej liczby deskryptorów plików, jeśli program ich używa.

Możesz patrzeć /usr/include/unistd.h jeśli je zapomnisz:

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

Powiedziałem, że napisałem narzędzia C, które używają niestandardowych rejestrów plików do niestandardowego logowania, więc nie widzisz go, chyba że przekierujesz go do pliku lub czegoś.


67
2018-05-03 22:58





Konstrukcja ta wysyła standardowy strumień błędów (stderr) do obecny lokalizacja standardowego wyjścia (stdout) - ta kwestia walutowa wydaje się być zaniedbywana przez inne odpowiedzi.

Możesz przekierować dowolny uchwyt wyjściowy na inny za pomocą tej metody, ale najczęściej jest używany do channelowania stdout i stderr strumienie do pojedynczego strumienia do przetworzenia.

Oto kilka przykładów:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

Zauważ, że ten ostatni będzie nie bezpośredni stderr do outfile2 - przekierowuje to do czego stdout było kiedy napotkano argument (outfile1) i następnie przekierowania stdout do outfile2.

Pozwala to na dość wyrafinowane oszustwo.


49
2018-05-03 23:54



Chociaż ten ostatni przykład byłby o wiele jaśniejszy, jak: foo> outfile2 2> outfile1 - Michael Cramer
Jaśniej, tak, ale to nie pokazałoby "pozycyjnego" charakteru przekierowania. Przykład jest wymyślny, ponieważ zwykle nie jest to przydatne w pojedynczej linii - metoda staje się bardzo użyteczna, gdy różne strony są odpowiedzialne za różne części przekierowania. Na przykład, gdy skrypt wykonuje jeden bit przekierowania i uruchamia go z innym bitem. - paxdiablo
Właśnie zdałem sobie sprawę, że ostatni przykład rozwiązuje również długo trwającą dezorientację dotyczącą tego: some_program 2>&1 > /dev/null nie działa w ten sposób: some_program > /dev/null 2>&1. - snapfractalpop
Twoja wypowiedź na temat ostatniego przykładu jest warta swoich listów w złocie :-) Nigdy nie myślałem, że te przekierowujące argumenty są pozycyjne ... Myślę, że to jest bardzo ważne, aby wiedzieć. - Nils-o-mat


Znalazłem ten świetny wpis na przekierowanie: Wszystko o przekierowaniach

Przekieruj zarówno standardowe wyjście, jak i standardowy błąd do pliku

$ command &> file

Ten jeden liniowiec używa &> operator, aby przekierować oba strumienie wyjściowe - stdout i stderr - z polecenia do pliku. Jest to skrót Basha do szybkiego przekierowania obu strumieni do tego samego miejsca docelowego.

Oto jak wygląda tabela deskryptorów plików po przekierowaniu obu strumieni przez Basha:

Enter image description here

Jak widać, zarówno standardowe wyjście, jak i stderr wskazują teraz file. Więc wszystko, co napisano na stdout i stderr, zostało napisane file.

Istnieje kilka sposobów przekierowania obu strumieni do tego samego miejsca docelowego. Możesz przekierować każdy strumień jeden po drugim:

$ command> file 2> & 1

Jest to znacznie powszechniejszy sposób przekierowania obu strumieni do pliku. Pierwsze wyjście standardowe jest przekierowywane do pliku, a następnie stderr jest duplikowane, aby było takie samo jak standardowe wyjście. Więc oba strumienie w końcu wskazują file.

Kiedy Bash widzi kilka przekierowań, przetwarza je od lewej do prawej. Przejdźmy przez kolejne etapy i zobaczmy, jak to się dzieje. Przed uruchomieniem jakichkolwiek poleceń tablica deskryptorów plików Basha wygląda następująco:

Enter image description here

Teraz Bash przetworzy pierwszy plik> przekierowania. Widzieliśmy to wcześniej i sprawia, że ​​stdout wskazuje na plik:

Enter image description here

Następny Bash dostrzega drugie przekierowanie 2> i 1. Nie widziałem tego wcześniejszego przekierowania. Ta kopia powiela deskryptor 2 pliku jako kopię deskryptora pliku 1 i otrzymujemy:

Enter image description here

Oba strumienie zostały przekierowane do pliku.

Jednak bądź ostrożny tutaj! Pisanie

polecenie> plik 2> i 1

to nie to samo, co pisanie:

$ command 2> & 1> file

Kolejność przekierowań ma znaczenie w Bash! To polecenie przekierowuje tylko standardowe wyjście do pliku. Stderr nadal będzie drukował na terminalu. Aby zrozumieć, dlaczego tak się dzieje, przejdźmy ponownie przez kolejne kroki. Tak więc przed uruchomieniem polecenia tabela deskryptorów plików wygląda następująco:

Enter image description here

Teraz Bash przetwarza przekierowania od lewej do prawej. Po raz pierwszy widzi 2> i 1, więc duplikuje stderr na stdout. Tablica deskryptorów plików staje się:

Enter image description here

Teraz Bash widzi drugie przekierowanie, >file, i przekierowuje standardowe wyjście do pliku:

Enter image description here

Czy widzisz, co się tutaj dzieje? Stdout wskazuje teraz na plik, ale stderr nadal wskazuje na terminal! Wszystko, co zostanie zapisane na stderr, zostanie wydrukowane na ekranie! Bądź więc bardzo, bardzo ostrożny z kolejnością przekierowań!

Zauważ też, że w Bash piszesz

$ command &> file

jest dokładnie taki sam jak:

$ command> & file


47
2017-10-29 13:04



Dwa ostatnie są różne, jeśli "command" kończy się liczbą, ponieważ wtedy jest to opcjonalne deskryptor pliku dla >& - M.M
wspaniałe wyjaśnienie! Dziękuję Ci - Vicer


2>&1 jest konstrukcją powłoki POSIX. Oto podział, token według tokena:


2: "Standardowy błąd"deskryptor pliku wyjściowego.

>&: Duplikuj deskryptor pliku wyjściowego operator (wariant Przekierowanie wyjścia operator >). Dany [x]>&[y], deskryptor pliku oznaczony przez x jest tworzony jako kopia deskryptora pliku wyjściowego y.

1 "Standardowe wyjście"deskryptor pliku wyjściowego.

Ekspresja 2>&1 kopiuje deskryptor pliku 1 do lokalizacji 2, więc wszelkie wyniki zapisane w 2 ("błąd standardowy") w środowisku wykonawczym przechodzi do tego samego pliku, który został pierwotnie opisany przez 1 ("standardowe wyjście").


Dalsze wyjaśnienia:

Deskryptor pliku: "Unikalna dla procesu, nieujemna liczba całkowita używana do identyfikacji otwartego pliku w celu uzyskania dostępu do pliku."

Standardowe wyjście / błąd: Zobacz następującą notatkę w pliku Przekierowanie sekcja dokumentacji powłoki:

Otwarte pliki są reprezentowane przez liczby dziesiętne zaczynające się od zera. Największa możliwa wartość jest definiowana przez implementację; jednak wszystkie wdrożenia obsługują co najmniej od 0 do 9, włącznie, do użytku przez aplikację. Liczby te nazywane są "deskryptorami plików". Wartości 0, 1 i 2 mają specjalne znaczenie i konwencjonalne zastosowania i są implikowane przez pewne operacje przekierowania; są one nazywane, odpowiednio, standardowym wejściem, standardowym wyjściem i standardowym błędem. Programy zwykle pobierają swoje dane ze standardowego wejścia i zapisują wyjście na standardowe wyjście. Komunikaty o błędach są zwykle zapisywane na standardowym błędzie. Operatory przekierowania mogą być poprzedzone jedną lub większą liczbą cyfr (bez dopuszczalnych znaków pośrednich), aby wyznaczyć numer deskryptora pliku.


13
2017-12-25 06:43





Aby odpowiedzieć na twoje pytanie: Przyjmuje wszystkie wyjścia błędów (zwykle wysyłane na stderr) i zapisuje je na standardowe wyjście (stdout).

Jest to pomocne, na przykład "więcej", gdy potrzebujesz stronicowania dla wszystkich danych wyjściowych. Niektóre programy, takie jak drukowanie informacji o użyciu na stderr.

Aby pomóc Ci zapamiętać

  • 1 = standardowe wyjście (gdy programy drukują normalne wyjście)
  • 2 = błąd standardowy (gdzie programy drukują błędy)

"2> i 1" po prostu wskazują wszystko wysłane do stderr, zamiast tego na standardowe wyjście.

Polecam również czytanie ten wpis dotyczący przekierowania błędu gdzie temat ten jest szczegółowo omówiony.


12
2018-05-03 23:24





2 to standardowy błąd konsoli.

1 to standardowe wyjście konsoli.

Jest to standardowy Unix, a Windows także działa zgodnie z POSIX.

Na przykład. kiedy uciekasz

perl test.pl 2>&1

standardowy błąd jest przekierowywany na standardowe wyjście, więc możesz zobaczyć oba wyjścia razem:

perl test.pl > debug.log 2>&1

Po wykonaniu można zobaczyć wszystkie dane wyjściowe, w tym błędy, w pliku debug.log.

perl test.pl 1>out.log 2>err.log

Następnie standardowe wyjście przechodzi do out.log, a standardowy błąd do err.log.

Proponuję ci spróbować to zrozumieć.


12
2017-07-19 03:23



Druga próbka jest błędna: jako pierwszeństwo kolejności STDERR zostaje przekierowany do STDOUT, tylko domyślne STDOUT zostanie napisany do debug.log (nie STDERR) widzieć moja odpowiedź (ustęp 2)! Aby zapewnić obie aby przekierować do tego samego pliku, musisz odwrócić dyrektywy przekierowania: perl test.pl > debug.log 2>&1 - F. Hauri


Z punktu widzenia programisty oznacza to dokładnie:

dup2(1, 2);

Zobacz strona man.

Zrozumienie tego 2>&1 jest Kopiuj wyjaśnia również, dlaczego ...

command >file 2>&1

... to nie to samo co ...

command 2>&1 >file

Pierwszy wyśle ​​oba strumienie do file, podczas gdy drugi wysyła błędy do stdouti zwykłe wyjście do file.


10
2017-12-03 10:20