Czy w bashu jest jakiś sposób na przepuszczenie STDERR przez filtr przed ujednoliceniem go z STDOUT? To znaczy chcę
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
zamiast
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘
Odpowiedzi:
Oto przykład wzorowany na tym, jak zamienić deskryptory plików w bash . Wynik a.out jest następujący, bez przedrostka „STDXXX:”.
STDERR: stderr output STDOUT: more regular ./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g' more regular stdErr output
Cytując z powyższego linku:
źródło
3>&2 2>&1 1>&3-
.TL; DR:
Przykład:
To zadziała zarówno w bash, jak i zsh. Bash jest obecnie prawie wszechobecny, jednak jeśli naprawdę potrzebujesz (naprawdę okrutnego) rozwiązania dla POSIX
sh
, zobacz tutaj .Wyjaśnienie
Zdecydowanie najłatwiejszym sposobem na to jest przekierowanie STDERR przez podstawianie procesów :
Więc to, co otrzymujesz po podstawieniu procesu, to nazwa pliku.
Tak jak możesz:
możesz to zrobić
>&2
Przekierowaniafilter
„s STDOUT z powrotem do pierwotnego stderr.źródło
exec 2> >(while .. read .. echo)
w skrypcie działającym jako usługa systemd. journald przechwytuje fd2 usługi i wnioskuje poziom dziennika z przedrostka „<N>”: dołączaj<2>
przed wierszami wyjściowymi i otrzymujesz poziom ERROR przypisany do rekordów dziennika. Ale czasami systemd szybciej zabijał całą grupę procesów po wyjściu z głównej, zanim zdążył zarejestrować ostatnią, najważniejszą wiadomość!Wydaje się, że naiwne stosowanie zastępowania procesów umożliwia filtrowanie
stderr
oddzielnie odstdout
::; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) out e:err
Zauważ, że
stderr
pojawia sięstderr
istdout
włączastdout
, co możemy zobaczyć, opakowując całość w inną podpowłokę i przekierowując do plikówo
ie
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e
źródło
$
jako wiersza poleceń. Wtedy często piszą powłoki przykłady takich jak:$ cat /var/log/syslog | fgrep ...
. Jednak tej linii nie można kopiować i wklejać ze względu na rozszerzenie$
.:;
wygląda jak zachęta, ale w zasadzie jest to powłoka nie działa; dzięki czemu można bezpiecznie zaznaczyć i wkleić całą linię.TL; DR: (bash i zsh)
Przykład:
Wiele odpowiedzi w sieci StackExchange ma postać:
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
Ma to wbudowane założenie: ten deskryptor pliku 3 nie jest używany do czegoś innego.
Zamiast tego użyj nazwanego deskryptora pliku i
{ba,z}sh
przydzieli następny dostępny deskryptor pliku> = 10:cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
Zauważ, że nazwane deskryptory plików nie są obsługiwane przez POSIX
sh
.Innym problemem związanym z powyższym jest to, że polecenie nie może być przesłane potokiem do dalszych poleceń bez ponownego zamiany STDOUT i STDERR z powrotem na ich oryginalne wartości.
Aby umożliwić
sh
dalsze przesyłanie rur w POSIX (i nadal zakładając, że FD 3 nie jest tego używany), sprawa się komplikuje :Tak więc, biorąc pod uwagę założenie i gnarly składnię tego, prawdopodobnie lepiej będzie, jeśli użyjesz prostszej
bash
/zsh
składni pokazanej w TL; DR powyżej i wyjaśnionej tutaj .źródło
Uważam, że podstawienie procesu bash jest łatwiejsze do zapamiętania i używania, ponieważ prawie dosłownie odzwierciedla pierwotny zamiar. Na przykład:
$ cat ./p echo stdout echo stderr >&2 $ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/' sTdout STderr
używa pierwszej komendy sed jako filtru tylko na stderr, a drugiej komendy sed do modyfikowania połączonych danych wyjściowych.
Zauważ, że spacja po 2> jest obowiązkowa, aby polecenie zostało poprawnie przeanalizowane.
źródło
Ostatnia część tej strony podręcznika Advanced Bash Scripting Guide to „przekierowywanie tylko stderr do potoku”.
To może być to, czego chcesz. Jeśli nie, jakaś inna część ABSG powinna ci pomóc, to jest doskonałe.
źródło
Spójrz na nazwane potoki:
źródło
cat - err
przerwie przeplatania się stdout i stderr?