Wyświetl stdout i stderr w dwóch osobnych strumieniach

13

Szukam sposobu wizualnego oddzielenia stdout i stderr, aby się nie przeplatały i aby można je było łatwo zidentyfikować. Idealnie, stdout i stderr miałyby oddzielne obszary na ekranie, w których są wyświetlane, np. W różnych kolumnach. Na przykład dane wyjściowe, które wyglądałyby tak:

~$ some command
some useful output info
ERROR: an error
more output
ERROR: has occurred
another message
~$ 

zamiast tego wyglądałby mniej więcej tak:

~$ some command          |
some useful output info  |
more output              |  ERROR: an error
another message          |  ERROR: has occurred
~$                       |
Zoey Hewll
źródło
Wydaje się, że to pytanie nie dotyczy tego samego i żadna z odpowiedzi nie zawiera tego, co tu postawiono.
Michael Homer,
2
Czy użyteczne byłoby przekierowanie strumieni do dwóch różnych plików dziennika, a następnie użycie na nich czegoś takiego jak MultiTail? vanheusden.com/multitail
Kusalananda
Czy narzędzie wyjściowe adnotacji wydaje się przydatne, czy potrzebujesz danych wyjściowych w kolumnach?
Jeff Schaller

Odpowiedzi:

5

Możesz użyć screenfunkcji podziału pionowego GNU :

#! /bin/bash -
tmpdir=$(mktemp -d) || exit
trap 'rm -rf "$tmpdir"' EXIT INT TERM HUP

FIFO=$tmpdir/FIFO
mkfifo "$FIFO" || exit

conf=$tmpdir/conf

cat > "$conf" << 'EOF' || exit
split -v
focus
screen -t stderr sh -c 'tty > "$FIFO"; read done < "$FIFO"'
focus
screen -t stdout sh -c 'read tty < "$FIFO"; eval "$CMD" 2> "$tty"; echo "[Command exited with status $?, press enter to exit]"; read prompt; echo done > "$FIFO"'
EOF

CMD="$*"
export FIFO CMD

screen -mc "$conf"

Aby użyć na przykład jako:

that-script 'ls / /not-here'

Chodzi o to, że uruchamia on ekran z tymczasowym plikiem conf, który uruchamia dwa okna ekranu w układzie podziału pionowego. W pierwszym uruchamiamy twoje polecenie z stderr podłączonym do drugiego.

Używamy nazwanego potoku dla drugiego okna, aby przekazać jego urządzenie tty do pierwszego, a także dla pierwszego, aby poinformować drugie, kiedy polecenie zostanie wykonane.

Inną zaletą w porównaniu z podejściami opartymi na potokach jest to, że stdout i stderr polecenia są nadal podłączone do urządzeń tty, więc nie wpływa to na buforowanie. Oba panele można również przewijać niezależnie w górę i w dół (w screentrybie kopiowania).

Jeśli uruchomisz powłokę podobnie jak bashinteraktywnie z tym skryptem, zauważysz, że monit zostanie wyświetlony w drugim oknie, podczas gdy powłoka będzie czytać to, co wpiszesz w pierwszym oknie, gdy powłoki wyrzucają swój monit na stderr.

W przypadku bash, w echo tego, co piszesz pojawi się również na drugim oknie jako że echo jest wyprowadzany przez powłokę (readline w przypadku bash) na stderr, jak również. Z niektórych innych skorup podoba ksh93, to pokaże na pierwszym oknie ( echo wyjście na terminalu sterownika, a nie shell), chyba że można umieścić w powłokę emacslub vitryb z set -o emacslub set -o vi.

Stéphane Chazelas
źródło
1

To brzydkie rozwiązanie oparte na annotate-outputskrypcie Debiana ANNOTATE-OUTPUT (1) . Nie jestem pewien, czy tego właśnie szukasz, ale może być coś na początek:

#!/bin/bash 

readonly col=150 # column to start error output 

add_out ()
{
    while IFS= read -r line; do
        echo "$1: $line"
    done
    if [ ! -z "$line" ]; then
        echo -n "$1: $line"
    fi
}

add_err ()
{
    while IFS= read -r line; do
        printf "%*s  %s %s: %s\n" $col "|" "$1" "$line"
    done
    if [ ! -z "$line" ]; then
        printf "%*s %s: %s" $col "$1" "$line"
    fi
}

cleanup() { __st=$?; rm -rf "$tmp"; exit $__st; }
trap cleanup 0
trap 'exit $?' 1 2 13 15

tmp=$(mktemp -d --tmpdir annotate.XXXXXX) || exit 1
OUT=$tmp/out
ERR=$tmp/err

mkfifo $OUT $ERR || exit 1

add_out OUTPUT < $OUT &
add_err ERROR < $ERR &

echo "I: Started $@"
"$@" > $OUT 2> $ERR ; EXIT=$?
rm -f $OUT $ERR
wait

echo "I: Finished with exitcode $EXIT"

exit $EXIT

Możesz to przetestować za pomocą ./this_script another_scriptlub command.

kubek kawy
źródło
1

Spróbuję przeanalizować następującą część twojego pytania:

zamiast tego wyglądałby mniej więcej tak:

 ~ $ jakaś komenda
 przydatne informacje o wyjściu |
 większa wydajność | BŁĄD: błąd
 kolejna wiadomość | Wystąpił błąd
 ~ $ 

Jeśli ktoś chciałby rozbić to, co chcesz:

1) stdoutStrumień nie kończyłby każdej linii znakiem, CR LFale zamiast niego znakiem „|” postać. Oczywiście nie wyrównałoby to dwóch strumieni, a wyrównanie nie wchodzi w rachubę, ponieważ musiałoby przewidzieć długość przyszłych linii dodanych do stdout, co oczywiście jest niemożliwe.

2) Zakładając, że zapominamy o wyrównaniu, po prostu wyprowadzilibyśmy stderrpo przetworzeniu przez potok, który dodaje „BŁĄD:” na początku każdej linii. Myślę, że jest to dość łatwe, tworząc prosty skrypt i upewniając się, że stderrzawsze wychodzi przez ten skrypt.

Ale to dałoby wynik:

~ $ jakaś komenda
 przydatne informacje o wyjściu |
 większa wydajność | BŁĄD: błąd
 kolejna wiadomość | Wystąpił błąd

Co tak naprawdę nie jest pomocne? Też nie wierzę, po to też jesteście!

Myślę, że problem z początkowym pytaniem polega na tym, że nie bierze się pod uwagę szeregowego charakteru każdej linii dołączonej do strumienia, w związku z tym, że oba strumienie mogą być zapisywane asynchronicznie.

Uważam, że najbliższym możliwym rozwiązaniem byłoby użycie ncurses.
Widzieć.
[ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[ http://invisible-island.net/ncurses/ncurses-intro.html#updating]

Aby zrobić to, co chcesz, musisz buforować oba strumienie i połączyć je, aby utworzyć trzeci bufor, który pobiera elementy z obu buforów. Następnie zrzuć trzeci bufor do ekranu terminala, usuwając ekran terminala i odmalowując go za każdym razem, gdy zmienia się trzeci bufor. Ale tak to ncursesdziała, więc po co wymyślać koło i nie zdejmować stamtąd?
W każdym razie musisz przejąć sposób, w jaki ekran terminala jest całkowicie pomalowany ! I wyrównaj tekst w przedrukowanej wersji ekranu, jak chcesz. Podobnie jak gra wideo z terminalnymi postaciami.
Mam nadzieję, że moja odpowiedź będzie pomocna w wyjaśnieniu ograniczeń tego, czego szukasz ...
Przepraszam za powtórzenie tego, ale największym problemem z tym, co pokazałeś, jest to, w jaki sposób „procesor” strumieni stdouti będzie stderrwiedział z góry o długości dodanych do niego przyszłych linii w celu ich prawidłowego wyrównania.

Angelos Asonitis
źródło