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?
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.
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).
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
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.
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:
- powstaje rura (fifo). "command FD1" jest wskazywany na ten przewód. "grep FD0" jest również wskazywany na tę rurę
- "polecenie FD2" jest wskazywane tam, gdzie "polecenie FD1" aktualnie wskazuje (rura)
- "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:
- tworzona jest rura i "polecenie FD 1" i "grep fd 0" są na nią wskazywane
- "polecenie FD 1" wskazuje na /dev / null
- "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ę.
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
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
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
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.
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.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'
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