Jak wykonać rurkę Stderr bez standardowej rury

24

Jak potokować standardowy strumień błędów bez potokowania standardowego strumienia wyjściowego?

Wiem, że to polecenie działa, ale wypisuje również standard.

Command 2>&1 | tee -a $LOG

Jak uzyskać tylko standardowy błąd?

Uwaga: Chcę z tego napisać strumień stderr do dziennika i napisać zarówno stderr, jak i stdout do konsoli.

Krzyż
źródło

Odpowiedzi:

26

Aby to zrobić, użyj jednego dodatkowego deskryptora pliku, aby przełączyć stderr i stdout:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

Zasadniczo działa, a przynajmniej myślę, że działa w następujący sposób:
Przekierowania są oceniane od lewej do prawej.

3>&1 Tworzy nowy deskryptor pliku, 3 duplikat (kopia) fd 1 (stdout).

1>&2 Uczyń stdout (1) duplikatem fd 2 (stderr)

2>&3 Stwórz fd 2, duplikat (kopię) 3, który wcześniej był kopią standardowego wyjścia.

Więc teraz stderr i stdout są przełączane.

| tee foo.file tee powiela deskryptor pliku 1, który został przekształcony w stderr.

Kyle Brandt
źródło
Och, nie testowałem z ksh, ale działa z bash ...
Kyle Brandt
Dzięki, działa również w ksh. Myślę, że większość rzeczy w potoku i strumieniu jest standardem posix.
C. Ross,
„Kopiowanie” nie jest naprawdę poprawne - patrz odpowiedź @ Guasqueño.
Kyle Brandt,
Działa to również w systemie Windows z tee.exezainstalowanym :)
Acorn
13

Polecenie Kyle'a dla systemu Unix / Linux ma za zadanie przełączanie STDERR za pomocą STDOUT; jednak wyjaśnienie nie jest całkiem poprawne. Operatorzy przekierowujący nie kopiują ani nie kopiują, po prostu przekierowują przepływ w innym kierunku.

Przepisanie polecenia Kyle'a poprzez tymczasowe przesunięcie 3> i 1 do końca ułatwiłoby zrozumienie koncepcji:

find /var/log  1>&2  2>&3  3>&1  

Napisany w ten sposób Linux wyświetli błąd, ponieważ & 3 jeszcze nie istnieje, ponieważ znajduje się przed 3> i 1. 3> coś jest sposobem na zadeklarowanie (zdefiniowanie), że użyjemy trzeciej rury, więc musi być zlokalizowana przed dopływem wody do tej rury, na przykład sposób, w jaki Kyle ją napisał. Spróbuj tego w inny sposób dla zabawy:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

Szkoda, że ​​nie można robić kopii. Nie możesz robić rzeczy takich jak „3> i 1 3> i 2” w tym samym poleceniu, ponieważ Linux użyje tylko pierwszego znalezionego i odrzuca drugi.

Nie znalazłem (jeszcze) sposobu, aby wysłać zarówno błąd, jak i zwykłe wyjście do pliku, a także wysłać kopię błędu do standardowego wyjścia za pomocą jednego polecenia. Na przykład mam zadanie cron, które chcę, aby oba dane wyjściowe (błąd i standard) trafiły do ​​pliku dziennika i pozwolić, aby błąd również zgasł, aby wiadomość e-mail została wysłana do mojego BlackBerry. Mogę to zrobić za pomocą dwóch poleceń za pomocą „tee”, ale błąd nie pojawia się we właściwej kolejności wśród zwykłych wierszy wyjściowych w pliku. W ten sposób rozwiązałem problem:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

Zauważ, że muszę użyć log1 dwa razy i muszę dołączyć w obu przypadkach, pierwszy używa opcji „-a” dla polecenia „tee”, a drugi używa „>>”.

Robiąc log kota 1 otrzymujesz:

STD1
STD2
-bash: sdfr: command not found

Zauważ, że błąd nie pojawia się w drugim wierszu tak, jak powinien.

Guasqueño
źródło
Niesamowita korekta!
Kyle Brandt,
Sprawdź zsh i mult_iosopcję (domyślnie włączone), aby móc przekierowywać FD wiele razy.
Tom Hale,
2

zgodnie ze stroną podręcznika dla ksh (pdksh), możesz po prostu:

Polecenie 2> i 1> / dev / null | cat -n

tzn. dup stderr do stdout, przekieruj stdout do / dev / null, a następnie potokuj do 'cat -n'

działa na pdksh w moim systemie:

$ errorecho () {echo "$ @"> & 2;}

$ errorecho foo
bla

$ errorecho foo> / dev / null # powinien nadal wyświetlać się nawet po przekierowaniu standardowego wyjścia
bla

$ errorecho foo 2> & 1> / dev / null | cat -n
     1 foo
$   
cas
źródło
Współpracuje również z BusyBox
Udo G
1

uruchomiłem go tak, jak kiedykolwiek chciałeś, ponieważ potrzebowałem go i dopracowałem twoje polecenie. teraz dla mnie działa poprawnie przy użyciu bash 3.2 na debian squeeze przy użyciu tego

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

podczas gdy log1 rejestruje stdout i stderr, a log2 rejestruje tylko stderr i nic więcej nie jest wyświetlane na ekranie.

martinseener
źródło