Exibir stdout e stderr em dois fluxos separados

12

Estou procurando uma maneira de separar visualmente stdout e stderr, para que eles não entremeados e possam ser facilmente identificados. Idealmente, stdout e stderr teriam áreas separadas na tela em que são exibidas, por exemplo, em colunas diferentes. Por exemplo, saída que seria assim:

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

seria algo parecido com isto:

~$ some command          |
some useful output info  |
more output              |  ERROR: an error
another message          |  ERROR: has occurred
~$                       |
Zoey Hewll
fonte
Essa pergunta não parece estar fazendo a mesma coisa, e nenhuma das respostas fornece o que é solicitado aqui.
Michael Homer
2
Seria útil redirecionar os fluxos para dois arquivos de log diferentes e usar algo como o MultiTail neles? vanheusden.com/multitail
Kusalananda
O utilitário de anotação de saída parece útil ou você precisa da saída em colunas?
Jeff Schaller

Respostas:

4

Você pode usar o screenrecurso de divisão vertical do 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 exemplo, como:

that-script 'ls / /not-here'

A idéia é que ele execute a tela com um arquivo conf temporário que inicie duas janelas de tela em um layout de divisão vertical. No primeiro, executamos seu comando com o stderr conectado ao segundo.

Usamos um pipe nomeado para a segunda janela para comunicar seu dispositivo tty ao primeiro e também para o primeiro informar o segundo quando o comando for executado.

A outra vantagem comparada às abordagens baseadas em pipe é que o stdout e o stderr do comando ainda estão conectados a dispositivos tty, portanto, isso não afeta o buffer. Os dois painéis também podem ser rolados para cima e para baixo de forma independente (usando screeno modo de cópia).

Se você executar um shell de maneira bashinterativa com esse script, notará que o prompt será exibido na segunda janela, enquanto o shell lerá o que você digita na primeira janela, conforme esses shells emitem seu prompt no stderr.

No caso de bash, o eco do que você digita também aparecerá na segunda janela, pois esse eco é emitido pelo shell (linha de leitura no caso de bash) no stderr também. Com algumas outras conchas gosta ksh93, ele vai mostrar na primeira janela ( eco saída pelo driver de dispositivo terminal, não o shell), a menos que você colocar o shell em emacsou vimodo com set -o emacsou set -o vi.

Stéphane Chazelas
fonte
1

Esta é uma solução feia baseada no annotate-outputscript do Debian ANNOTATE-OUTPUT (1) . Não tenho certeza se é isso que você está procurando, mas pode ser algo para começar:

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

Você pode testá-lo usando ./this_script another_scriptou command.

coffeMug
fonte
1

Vou tentar analisar a seguinte parte da sua pergunta:

seria algo parecido com isto:

 ~ $ some command
 algumas informações úteis sobre saída |
 mais saída | ERRO: um erro
 outra mensagem | Um erro ocorreu
 ~ $ 

Se alguém quiser dividir o que você quer é:

1) O stdoutfluxo não terminaria cada linha com um, CR LFmas com um '|' personagem. Isso não alinharia os dois fluxos, é claro, e o alinhamento está fora de questão, pois teria que prever a extensão das linhas futuras adicionadas ao stdout, o que é obviamente impossível.

2) Supondo que esquecemos o alinhamento, simplesmente produziríamos o resultado stderrapós o processamento por um pipeline que adiciona "ERRO:" ao início de cada linha. Suponho que isso seja muito fácil, criando um script simples e verifique se o stderrsempre sai através desse script.

Mas isso criaria uma saída como esta:

~ $ some command
 algumas informações úteis sobre saída |
 mais saída | ERRO: um erro
 outra mensagem | Um erro ocorreu

O que não é realmente útil, é? Também não acredito, é o que você está procurando também!

O problema com a pergunta inicial, acho que é que você não leva em conta a natureza serial de cada linha anexada em um fluxo, em conexão com o fato de que ambos os fluxos podem ser gravados de forma assíncrona.

Eu acredito que a solução mais próxima possível seria usar ncurses.
Vejo.
[ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[ http://invisible-island.net/ncurses/ncurses-intro.html#updating]

Para fazer o que você procura, você precisa armazenar em buffer os dois fluxos e combiná-los para produzir um terceiro buffer que use elementos de ambos os buffers. Em seguida, despeje o terceiro buffer na tela do terminal apagando a tela do terminal e repintando-o cada vez que o terceiro buffer for alterado. Mas é assim que ncursesfunciona, então por que reinventar a roda e não levá-la de lá?
De qualquer forma, você teria que assumir o controle da tela do terminal inteiramente ! E realinhe o texto na versão reimpressa da tela como desejar. Muito parecido com um videogame com personagens terminais.
Espero que minha resposta seja útil para esclarecer as limitações do que você procura ...
Desculpe-me por repetir isso, mas o maior problema com o que você mostrou é como o "processador" dos fluxos stdoute stderrsaberá antecipadamente o tamanho das futuras linhas adicionadas a ele para alinhá-las corretamente.

Angelos Asonitis
fonte