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.