Mostrar stdout y stderr en dos secuencias separadas

Mostrar stdout y stderr en dos secuencias separadas

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 las que se muestran, por ejemplo, en columnas diferentes. Por ejemplo, una 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 así:

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

Respuesta1

Podrías 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 ejecute la pantalla con un archivo conf temporal que inicie dos ventanas de pantalla en un diseño dividido verticalmente. En el primero, ejecutamos tu comando con el stderr conectado al segundo.

Usamos una canalización con nombre para que la segunda ventana comunique su dispositivo tty a la primera, y también para que la primera le diga a la segunda cuando finaliza 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 (usando screenel modo de copia).

Si ejecuta un shell de forma bashinteractiva con ese script, notará que el mensaje 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 mensaje en stderr.

En el caso de bash, elecode lo que escriba también aparecerá en la segunda ventana, ya queecobashTambién lo genera el shell (readline en el caso de ) en stderr. Con algunos otros shells como ksh93, se mostrará en la primera ventana (ecosalida del controlador del dispositivo terminal, no del shell), a menos que coloque el shell en modo emacso vicon set -o emacso set -o vi.

Respuesta2

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

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

Respuesta3

Intentaré analizar la siguiente parte de tu pregunta:

en su lugar se vería así:

~$ algún comando
 alguna información de salida útil |
 más producción | 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 con un CR LFsino con 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 al archivo stdout, lo cual, por supuesto, es imposible.

2) Suponiendo que nos olvidamos 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 haciendo un script simple y asegurándose de que stderrsiempre salga a través de este script.

Pero eso crearía una salida como esta:

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

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

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

Creo que la solución más cercana posible sería utilizar 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 busca, necesita almacenar en buffer ambos flujos y combinarlos para producir un tercer buffer que tome elementos de ambos buffers. Luego, descargue el tercer búfer en la pantalla del terminal borrando la pantalla del terminal y volviéndola a pintar cada vez que cambie el tercer búfer. Pero así es como ncursesfunciona, así que ¿por qué reinventar la rueda y no empezar desde ahí?
En cualquier caso, habría quehacerse cargo de la forma en que se pinta la pantalla del terminal por completo! Y realinee el texto en la versión reimpresa de la pantalla como desee. Muy parecido a un videojuego con personajes terminales.
Espero que mi respuesta sea útil para aclarar las limitaciones de lo que busca...
Disculpe por repetir esto, pero el mayor problema con lo que mostró es cómo sabrá el "procesador" de las stdouttransmisiones y stderrde antemano la duración de la Se le agregarán líneas futuras para alinearlas correctamente.

información relacionada