Visualizza stdout e stderr in due flussi separati


12

Sto cercando un modo per separare visivamente stdout e stderr, in modo che non si alternino e che possano essere facilmente identificati. Idealmente, stdout e stderr avrebbero aree separate sullo schermo in cui sono visualizzate, ad esempio in colonne diverse. Ad esempio, un output che sarebbe stato simile al seguente:

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

sarebbe invece simile a questo:

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


Questa domanda non sembra porre la stessa cosa e nessuna delle risposte fornisce ciò che viene chiesto qui.
Michael Homer,

2
Sarebbe utile reindirizzare i flussi su due diversi file di registro e quindi utilizzare qualcosa come MultiTail su di essi? vanheusden.com/multitail
Kusalananda

L'utilità di output annotato sembra utile o hai bisogno dell'output in colonne?
Jeff Schaller

Risposte:


4

È possibile utilizzare la screenfunzione di divisione verticale di 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"

Per usare ad esempio come:

that-script 'ls / /not-here'

L'idea è che esegue lo schermo con un file di configurazione temporaneo che avvia due finestre dello schermo in un layout diviso verticale. Nel primo, eseguiamo il tuo comando con lo stderr collegato al secondo.

Usiamo una pipe denominata per la seconda finestra per comunicare il suo dispositivo tty alla prima, e anche per la prima per dire alla seconda quando il comando è fatto.

L'altro vantaggio rispetto agli approcci basati su pipe è che lo stdout e lo stderr del comando sono ancora connessi ai dispositivi tty, quindi non influisce sul buffering. Entrambi i riquadri possono anche essere fatti scorrere su e giù indipendentemente (usando screenla modalità di copia).

Se esegui una shell in modo bashinterattivo con quello script, noterai che il prompt verrà visualizzato nella seconda finestra, mentre la shell leggerà ciò che digiti nella prima finestra mentre quelle shell emettono il loro prompt su stderr.

Nel caso di bash, l' eco di ciò che digiti apparirà anche nella seconda finestra poiché quell'eco viene emesso dalla shell (readline nel caso di bash) anche su stderr. Con alcune shell simili ksh93, verrà mostrata nella prima finestra ( output dell'eco dal driver del dispositivo terminale, non dalla shell), a meno che non si inserisca la shell emacso la vimodalità con set -o emacso set -o vi.


1

Questa è una brutta soluzione basata sullo annotate-outputscript di Debian ANNOTATE-OUTPUT (1) . Non sono sicuro se questo è quello che stai cercando, ma potrebbe essere qualcosa con cui iniziare:

#!/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

Puoi provarlo usando ./this_script another_scripto command.


1

Proverò ad analizzare la seguente parte della tua domanda:

sarebbe invece simile a questo:

 ~ $ un comando
 alcune utili informazioni di output |
 più output | ERRORE: un errore
 un altro messaggio | ERRORE: si è verificato
 ~ $ 

Se si volesse abbattere ciò che si desidera è:

1) Il stdoutflusso non terminerebbe ogni riga con un CR LFma invece con un '|' personaggio. Ciò non allineerebbe naturalmente i due flussi e l'allineamento è fuori discussione perché dovrebbe prevedere la lunghezza delle linee future aggiunte a stdout, il che è ovviamente impossibile.

2) Supponendo che dimentichiamo l'allineamento, avremmo semplicemente emesso il stderrdopo essere stato elaborato da una pipeline che aggiunge "ERRORE:" all'inizio di ogni riga. Suppongo che sia abbastanza facile creando uno script semplice e assicurandomi che stderresca sempre attraverso questo script.

Ma ciò creerebbe un output come questo:

~ $ un comando
 alcune utili informazioni di output |
 più output | ERRORE: un errore
 un altro messaggio | ERRORE: si è verificato

Quale non è davvero utile, vero? Inoltre non ci credo, è quello che cerchi anche tu!

Il problema con la domanda iniziale, penso sia che non si tiene conto della natura seriale di ogni riga aggiunta in un flusso, in relazione al fatto che entrambi i flussi possono essere scritti in modo asincrono.

Credo che la soluzione più vicina possibile sarebbe usare ncurses.
Vedere.
[ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[ http://invisible-island.net/ncurses/ncurses-intro.html#updating]

Per fare ciò che sei dopo devi bufferizzare entrambi i flussi e combinarli per produrre un terzo buffer che prende elementi da entrambi i buffer. Quindi scaricare il terzo buffer nella schermata del terminale cancellando la schermata del terminale e riverniciandolo ogni volta che cambia il terzo buffer. Ma ncursesfunziona così, quindi perché reinventare la ruota e non sollevarla da lì?
In ogni caso, dovresti assumere il modo in cui lo schermo del terminale è interamente dipinto ! E riallinea il testo nella versione ristampata dello schermo come preferisci. Proprio come un videogioco con personaggi terminali.
Spero che la mia risposta possa essere utile per chiarire i limiti di ciò che stai cercando ...
Mi scusi per averlo ripetuto, ma il problema più grande con quello che hai mostrato è come il "processore" dei flussi stdoute e stderrsaprà in anticipo la lunghezza delle linee future aggiunte ad esso per allinearli correttamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.