Muestra stdout y stderr en dos transmisiones separadas

12

Estoy buscando una manera de separar visualmente stdout y stderr, para que no se intercalen y puedan identificarse fácilmente. Idealmente, stdout y stderr tendrían áreas separadas en la pantalla en la que se muestran, por ejemplo, en diferentes columnas. Por ejemplo, salida que se vería así:

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

en su lugar se vería algo así:

~$ some command          |
some useful output info  |
more output              |  ERROR: an error
another message          |  ERROR: has occurred
~$                       |
Zoey Hewll
fuente
Esa pregunta no parece ser la misma, y ​​ninguna de las respuestas proporciona lo que se pregunta aquí.
Michael Homer
2
¿Sería útil redirigir las transmisiones a dos archivos de registro diferentes y luego usar algo como MultiTail en ellas? vanheusden.com/multitail
Kusalananda
¿La utilidad annotate-output parece útil, o necesita la salida en columnas?
Jeff Schaller

Respuestas:

4

Puede usar screenla función de división vertical de 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"

Para usar por ejemplo como:

that-script 'ls / /not-here'

La idea es que ejecuta la pantalla con un archivo de configuración temporal que inicia dos ventanas de pantalla en un diseño dividido vertical. En el primero, ejecutamos su comando con el stderr conectado al segundo.

Usamos una tubería con nombre para la segunda ventana para comunicar su dispositivo tty a la primera, y también para que la primera le diga a la segunda cuando se complete el comando.

La otra ventaja en comparación con los enfoques basados ​​en tuberías es que stdout y stderr del comando todavía están conectados a dispositivos tty, por lo que no afecta el almacenamiento en búfer. Ambos paneles también se pueden desplazar hacia arriba y hacia abajo de forma independiente (utilizando screenel modo de copia).

Si ejecuta un shell de forma bashinteractiva con ese script, notará que el indicador se mostrará en la segunda ventana, mientras que el shell leerá lo que escriba en la primera ventana a medida que esos shells muestren su indicador en stderr.

En el caso de bash, el eco de lo que escribe también aparecerá en la segunda ventana a medida que ese eco es emitido por el shell (readline en el caso de bash) también en stderr. Con algunas otras conchas les gusta ksh93, se mostrará en la primera ventana ( eco de salida por el controlador de dispositivo de terminal, no la cáscara), a menos que poner la cáscara en emacso vimodo con set -o emacso set -o vi.

Stéphane Chazelas
fuente
1

Esta es una solución fea basada en el annotate-outputscript de Debian ANNOTATE-OUTPUT (1) . No estoy seguro de si esto es lo que está buscando, pero podría ser algo para comenzar:

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

Puedes probarlo usando ./this_script another_scripto command.

taza de cafe
fuente
1

Intentaré analizar la siguiente parte de su pregunta:

en su lugar se vería algo así:

 ~ $ algún comando
 alguna información de salida útil |
 más salida | ERROR: un error
 otro mensaje | Un error ha ocurrido
 ~ $ 

Si uno quisiera desglosar lo que quiere es:

1) La stdoutsecuencia no terminaría cada línea CR LFcon un "|" personaje. Por supuesto, esto no alinearía las dos corrientes, y la alineación está fuera de discusión porque tendría que predecir la longitud de las líneas futuras agregadas a la stdout, que por supuesto es imposible.

2) Suponiendo que nos olvidemos de la alineación, simplemente generaríamos el resultado stderrdespués de ser procesado por una tubería que agrega "ERROR:" al comienzo de cada línea. Supongo que esto es bastante fácil al hacer un guión simple y asegurarse de que stderrsiempre salga a través de este guión.

Pero eso crearía una salida como esta:

~ $ algún comando
 alguna información de salida útil |
 más salida | ERROR: un error
 otro mensaje | Un error ha ocurrido

¿Qué no es realmente útil, verdad? Además, no creo, ¡es lo que buscas también!

Creo que el problema con la pregunta inicial es que no se tiene en cuenta la naturaleza en serie de cada línea agregada en una secuencia, en relación con el hecho de que ambas secuencias pueden escribirse de forma asíncrona.

Creo que la solución más cercana posible sería usar ncurses.
Ver.
[ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[ http://invisible-island.net/ncurses/ncurses-intro.html#updating]

Para hacer lo que está haciendo, necesita almacenar ambas secuencias y combinarlas para producir una tercera memoria intermedia que tome elementos de ambas memorias intermedias. Luego, descargue el tercer búfer en la pantalla del terminal borrando la pantalla del terminal y repintando cada vez que cambie el tercer búfer. Pero así es como ncursesfunciona, entonces ¿por qué reinventar la rueda y no levantarla desde allí?
En cualquier caso, ¡tendría que asumir la forma en que la pantalla del terminal está pintada por completo ! Y vuelva a alinear el texto en la versión reimpresa de la pantalla a su gusto. Al igual que un videojuego con personajes terminales.
Espero que mi respuesta sea útil para aclarar las limitaciones de lo que buscas ...
Disculpe por repetir esto, pero el mayor problema con lo que mostró es cómo sabrá el "procesador" de las secuencias stdouty stderrde antemano la longitud de las líneas futuras agregadas para alinearlas correctamente.

Angelos Asonitis
fuente