Po co przekierowywać wyjście do 2> i 1 oraz 1> i 2?


36

Natknąłem się na kilka poleceń, które używają 2>&1i 1>&2, ale nie mogę się skupić na celu użycia i kiedy powinienem go używać.

Co rozumiem

Wiem, że 1reprezentuje standardowe wyjście i 2standardowy błąd. Rozumiem, że 2>&1łączy wydajność 2do 1i odwrotnie.

Czego nie dostaję

  1. Kiedy powinienem go używać?
  2. Do czego to służy?

Odpowiedzi:


39

Czasami chcesz przekierować zarówno stdout, jak i stderr do tej samej lokalizacji. To >&jest używane - wskazuje jeden deskryptor pliku na inny.


Na przykład, jeśli chcesz zapisać stdout i stderr do tego samego pliku (czy to /dev/nulllub output.txt), możesz przekierować je osobno, za pomocą

app 1>/dev/null 2>/dev/null

lub możesz przekierować jeden deskryptor pliku do pliku, a drugi deskryptor pliku do pierwszego:

app 1>/dev/null 2>&1

app 2>/dev/null 1>&2

W pierwszym przykładzie 2>&1wskazuje deskryptor pliku nr 2 w miejsce, w którym numer 1 już wskazuje. Drugi przykład osiąga to samo, zaczynając od stderr zamiast tego.

Jako kolejny przykład zdarzają się przypadki, gdy stdout (deskryptor pliku # 1) wskazuje już żądaną lokalizację, ale nie można odwoływać się do niej po nazwie (może to być związane z potokiem, gniazdem itp.). Zdarza się to często, gdy używa się rozszerzenia procesu ( ` `lub $( )operatorów), które zwykle przechwytuje tylko standardowe wyjście, ale możesz chcieć uwzględnić w nim standard. W takim przypadku użyłbyś również >&do wskazania stderr na stdout:

out=$(app 2>&1)

Innym częstym przykładem jest pager greplub podobne narzędzie, ponieważ rura |zwykle działa tylko na stdout, przed użyciem potoku przekierujesz stderr na stdout:

app 2>&1 | grep hello

Jak wiemy, które z 2>&1lub 1>&2jest poprawna? Już skonfigurować deskryptor idzie z prawej strony >&, a deskryptor pliku, który chcesz przekierować idzie w lewo. ( 2>&1oznacza „wskaż deskryptor pliku nr 2 na deskryptor pliku nr 1”).


Niektóre powłoki mają skróty do typowych przekierowań; oto przykłady z Bash:

  • 1> można skrócić do just >

  • 1>foo 2>&1do >&foolub&>foo

  • 2>&1 | program do |& program


Nie miałem pojęcia, że ​​zrobienie app 1>/dev/null 2>&1tego oznaczałoby, że 2> i 1 wskazywałyby na plik, do którego 1 już przekierowywał. Rozumiem, że mógłbym równie łatwo zrobić app > /dev/null &>?
PeanutsMonkey

Trudno mi zrozumieć the already set up fd goes to the right of >&, and the fd you want to redirect goes to the left. Co rozumiesz przez już skonfigurowany deskryptor pliku? Co to oznacza prawo?
PeanutsMonkey


Przepraszam, chyba że masz zamiar uczyć mnie wskazówek, nie stosuję się do oświadczenia, które napisałeś wcześniej.
PeanutsMonkey

1
Każdego przekierowuj deskryptor pliku od lewej do prawej i stosuj te reguły w tej kolejności. Jeśli najpierw przekierujesz stdout do pliku, a następnie przekierujesz stderr do miejsca, w którym stdout nas teraz wskazuje, wtedy stderr i stdout przejdą do tego samego pliku. Jeśli zamienisz te dwa przekierowania, uzyskasz różne wyniki (przekieruj stderr do miejsca, w którym teraz idzie stdout , a następnie przesuń stdout, aby wskazał inny plik, podczas gdy stderr będzie kontynuował tam, gdzie był wskazywany).
Jason

2

Jedną z sytuacji, kiedy jest to potrzebne, jest wyświetlenie stracewyniku w pager. stracewypisuje swoje wyjście na standardowy błąd, a potoki zazwyczaj łączą standardowe wyjście ze standardowym wejściem, więc musisz użyć przekierowania:

strace -p $pid 2>&1 | less

Co masz na myśli pipes generally connect standard output to standard input?
PeanutsMonkey

2
Mam na myśli, że pipe ( |) pobiera standardowe wyjście pierwszego polecenia i łączy je ze standardowym wejściem drugiego polecenia.
jpalecek

2

Czasami chcesz przekierować zarówno stdout( 1), jak i stderr( 2) do tej samej lokalizacji ( /dev/nullna przykład). Jednym ze sposobów osiągnięcia tego byłoby:

$ program 1>/dev/null 2>/dev/null

Ale większość ludzi to skrócić poprzez przekierowanie stderrdo stdoutz 2>&1:

$ program 1>/dev/null 2>&1

Jeszcze krótsza wersja to:

$ program >&- 2>&-

1

2: To jest, kiedy będziesz miał wyjście zarówno ze standardowego błędu, jak i ze standardowego wyjścia, i chcesz, aby były one złożone w jeden ciąg.

1: Gdy chcesz manipulować wyjściem zarówno standardowego błędu, jak i standardowego wyjścia.


Co rozumiesz przez manipulowanie? Rozumiem, że cokolwiek przekierowane >2jest wysyłane do / dev / null. A może całkowicie źle to zrozumiałem?
PeanutsMonkey

To nie jest poprawne. Przez manipulowanie rozumiem potok to grep lub coś podobnego. Zobacz tutaj przykład.
soandos

0

Używam go, aby rozpocząć odłączoną pracę:

someProgram 2>&1 >& my.log &

wtedy mogę się wylogować, a niektóre programy będą nadal działać. Funkcjonalność zapewnia GNU Screen, tmux i niektóre inne programy - ale tutaj jest to osiągane bez żadnych zewnętrznych zależności.


1
Działa to tylko, dopóki do programu nie zostanie wysłany SIGHUP. Lepsze wykorzystanie nohuplub disownw takich przypadkach.
slhck

@slhck: ok. Ale jeśli nie wyślę SIGHUP do programu - nikt tego nie zrobi, prawda?
Adobe

Nie, terminal sterujący ostrzeże procesy wylogowania za pomocą SIGHUP. W praktyce, jeśli uruchomisz zdalną powłokę przez SSH i wyjdziesz, proces również umrze, na przykład.
slhck

@slhck: Nie może być prawdą: używam go przez kilka lat - wylogowuję się z ssh, a proces wciąż trwa.
Adobe

Będę musiał przyjrzeć się temu bardziej szczegółowo, ale samo umieszczenie programów w tle nie we mnie działało we wszystkich przypadkach, a na pewno nie działa nawet na moim komputerze lokalnym. Wygląda na to, że Zsh i Bash również zachowują się inaczej.
slhck

0

Wyobraź sobie, że istnieje katalog o trytych trzech plikach:file file1 and file2.

Teraz uruchom to polecenie:

cat file file1 file2 file3

Pierwsze trzy pliki są otwarte, ale catzgłasza błąd podczas otwierania czwartego, ponieważ nie istnieje.

Teraz uruchom:

cat file file1 file2 file3 1>outfile 2>&1

Nie widzę żadnego wyjścia na ekranie: Po pierwsze 1>outfilebędzie przekierowywać wyjście polecenie outfile, a następnie nastąpi przekierowanie ( 2>&1) błąd rzucony podczas próby otwarcia file3się outfile.

1>&2 działa podobnie i przekierowuje strumień błędów na standardowe wyjście.

Mam nadzieję że to pomoże!


0

Alternatywny scenariusz: polecenia terminala pokazują dane wyjściowe w innym terminalu

Użyj ttypolecenia w każdym terminalu, aby je zidentyfikować:

$ tty
/dev/pts/0

$ tty
/dev/pts/1

Zakładając te TTY, aby przekierować stdout pierwszego na drugi, uruchom to w pierwszym terminalu:

exec 1>/dev/pts/1

Uwaga: Teraz każde wyjście komendy będzie wyświetlane na pts / 1

Aby przywrócić domyślne zachowanie standardowego punktu pts / 0:

exec 1>/dev/pts/0

Obejrzyj ten film, aby zobaczyć demonstrację.


0

Omówiono już przypadek przekierowania stderr na stdout (np. Użyj go do filtrowania komunikatów o błędach (grep)).

Drugi przypadek to przekierowanie stdout na stderr. Częstym przypadkiem (przynajmniej dla mnie) jest wysyłanie ostrzeżeń / komunikatów o błędach wydrukowanych za pomocą „echa” (w moich skryptach powłoki) do stderr (aby łatwiej mogli zwrócić uwagę użytkownika).

Na przykład,

echo "file \"${file\" does not exist..." 1>&2
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.