Jak podłączyć stderr, a nie stdout?

Mam program, który zapisuje informacje do stdout i stderr, i muszę grep przez to, co nadchodzi do stderr , pomijając stdout.

Mogę oczywiście zrobić to w 2 krokach:

command > /dev/null 2> temp.file
grep 'something' temp.file

Ale wolałbym być w stanie to zrobić bez plików tymczasowych. Czy są jakieś mądre sztuczki z orurowaniem?

Author: Jonathan Leffler, 2010-02-26

10 answers

Najpierw przekierowanie stderr do stdout-rury; następnie przekierowanie stdout do /dev/null (bez zmiany miejsca, w którym stderr zmierza):

command 2>&1 >/dev/null | grep 'something'

Aby uzyskać szczegółowe informacje na temat przekierowań we / wy we wszystkich jego odmianach, zobacz Rozdział przekierowania w podręczniku referencyjnym Bash.

Należy zauważyć, że sekwencja przekierowań We/Wy jest interpretowana od lewej do prawej, ale rury są ustawiane przed interpretacją przekierowań We / Wy. Deskryptory plików, takie jak 1 i 2, są odniesieniami do opisów otwartych plików. Operacja 2>&1 sprawia, że deskryptor pliku 2 aka stderr odnosi się do tego samego opisu otwartego pliku, do którego obecnie odnosi się deskryptor pliku 1 aka stdout (zobacz dup2() oraz open()). Operacja >/dev/null zmienia deskryptor pliku 1 tak, że odnosi się do opisu otwartego pliku dla /dev/null, ale to nie zmienia faktu, że deskryptor pliku 2 odnosi się do opisu otwartego pliku, na który deskryptor pliku 1 pierwotnie wskazywał - mianowicie potoku.

 931
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-04 17:14:01

Lub zamiana wyjścia ze stderr i stdout na użycie: -

command 3>&1 1>&2 2>&3

Tworzy nowy deskryptor pliku (3) i przypisuje go do tego samego miejsca co 1 (stdout), następnie przypisuje fd 1 (stdout) do tego samego miejsca co fd 2 (stderr) i na koniec przypisuje FD 2 (stderr) do tego samego miejsca co FD 3 (stdout). Stderr jest teraz dostępny jako stdout i stare stdout zachowane w stderr. Może to być przesada, ale miejmy nadzieję, że da więcej szczegółów na temat deskryptorów plików bash(każdy proces ma 9 dostępnych).

 313
Author: Kramish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-15 09:09:12

W Bash, możesz również przekierować do podshell ' a używając process substitution :

command > >(stdlog pipe)  2> >(stderr pipe)

Dla rozpatrywanej sprawy:

command 2> >(grep 'something') >/dev/null
 177
Author: Rich Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-02 20:03:37

Łącząc najlepsze z tych odpowiedzi, jeśli to zrobisz:

command 2> >(grep -v something 1>&2)

...następnie wszystkie stdout są zachowywane jako stdout i wszystkie stderr są zachowywane jako stderr, ale w stderr nie zobaczysz żadnych linii zawierających łańcuch "something".

Ma to tę wyjątkową zaletę, że nie cofamy ani nie odrzucamy stdout i stderr, ani nie mieszamy ich razem, ani nie używamy żadnych plików tymczasowych.

 142
Author: Pinko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-22 03:03:56

O wiele łatwiej jest wizualizować rzeczy, jeśli myślisz o tym, co naprawdę dzieje się z "przekierowaniami" i "rurami."Przekierowania i rury w bash robią jedną rzecz: modyfikują miejsce, do którego wskazują deskryptory plików 0, 1 i 2 procesu (zobacz /proc/[pid]/fd/*).

Gdy w wierszu poleceń obecny jest operator pipe lub"|", pierwszą rzeczą, która się wydarzy, jest to, że bash tworzy fifo i kieruje FD 1 polecenia po lewej stronie do tego fifo, A FD 0 polecenia po prawej stronie do tego samego fifo.

Następnie operatory przekierowania dla każdej strony są oceniane od lewej do prawej, a bieżące ustawienia są używane za każdym razem, gdy występuje duplikacja deskryptora. Jest to ważne, ponieważ ponieważ rura została ustawiona jako pierwsza, FD1 (lewa strona) i FD0 (prawa strona) są już zmienione z tego, co normalnie mogło być, a każde ich powielenie będzie odzwierciedlać ten fakt.

Dlatego gdy wpiszesz coś w stylu:

command 2>&1 >/dev/null | grep 'something'

Oto co dzieje się w kolejności:

  1. powstaje rura (fifo). "command FD1" jest wskazywany na ten przewód. "grep FD0" jest również wskazywany na tę rurę
  2. "polecenie FD2" jest wskazywane tam, gdzie "polecenie FD1" aktualnie wskazuje (rura)
  3. "polecenie FD1" wskazuje na /dev / null

Tak więc wszystkie dane wyjściowe, które" command " zapisuje do swojego FD 2 (stderr), trafiają do potoku i są odczytywane przez "grep" po drugiej stronie. Wszystkie dane wyjściowe, które" command " zapisuje do swojego FD 1 (stdout), trafiają do / dev / null.

Jeśli zamiast tego uruchamiasz:

command >/dev/null 2>&1 | grep 'something'

Oto co się dzieje:

  1. tworzona jest rura i "polecenie FD 1" i "grep fd 0" są na nią wskazywane
  2. "polecenie FD 1" wskazuje na /dev / null
  3. "polecenie FD 2" wskazuje miejsce, w którym aktualnie wskazuje FD 1 (/dev/null)

Więc wszystkie stdout i stderr z "command" przechodzą do /dev/null. Nic nie idzie do rury, a tym samym "grep" zamknie się bez wyświetlania czegokolwiek na ekran.

Należy również pamiętać, że przekierowania (deskryptory plików) mogą być tylko do odczytu ( ) lub do odczytu ().

Ostatnia uwaga. To, czy program napisze coś do FD1 czy FD2, zależy wyłącznie od programisty. Dobra praktyka programowania nakazuje, że komunikaty o błędach powinny trafiać do FD 2, a normalne wyjście do FD 1, ale często znajdziesz niechlujne programowanie, które miesza te dwa lub w inny sposób ignoruje konwencję.

 86
Author: Michael Martinez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-20 18:18:28

Używasz Basha? Jeżeli tak:

command >/dev/null |& grep "something"

Http://www.gnu.org/software/bash/manual/bashref.html#Pipelines

 28
Author: Ken Sharp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-18 21:56:16

Dla tych, którzy chcą przekierować stdout i stderr na stałe do plików, grep na stderr, ale zachowaj stdout, aby pisać wiadomości do tty:

# save tty-stdout to fd 3
exec 3>&1
# switch stdout and stderr, grep (-v) stderr for nasty messages and append to files
exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out
# goes to the std.out
echo "my first message" >&1
# goes to the std.err
echo "a error message" >&2
# goes nowhere
echo "this nasty_msg won't appear anywhere" >&2
# goes to the tty
echo "a message on the terminal" >&3
 9
Author: JBD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-04 08:05:20

Spowoduje to przekierowanie command1 stderr na command2 stdin, pozostawiając command1 stdout w takim stanie, w jakim jest.

exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-

Wzięte z LDP

 5
Author: theDolphin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-07 07:39:05

Właśnie wymyśliłem rozwiązanie wysyłania stdout do jednej komendy i stderr do drugiej, używając nazwanych rur.

Zaczyna się.
mkfifo stdout-target
mkfifo stderr-target
cat < stdout-target | command-for-stdout &
cat < stderr-target | command-for-stderr &
main-command 1>stdout-target 2>stderr-target
Prawdopodobnie dobrym pomysłem jest usunięcie nazwanych rur.
 1
Author: Tripp Kinetics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-09 18:35:48

Staram się śledzić, znaleźć to działa, jak również,

command > /dev/null 2>&1 | grep 'something'
 -3
Author: lasteye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-13 08:07:05