Anzeige von stdout und stderr in zwei getrennten Streams

Anzeige von stdout und stderr in zwei getrennten Streams

Ich suche nach einer Möglichkeit, stdout und stderr optisch zu trennen, damit sie sich nicht vermischen und leicht zu erkennen sind. Idealerweise hätten stdout und stderr separate Bereiche auf dem Bildschirm, in denen sie angezeigt werden, z. B. in unterschiedlichen Spalten. Eine Ausgabe hätte beispielsweise so ausgesehen:

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

würde stattdessen ungefähr so ​​aussehen:

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

Antwort1

Sie könnten screendie vertikale Teilungsfunktion von GNU verwenden:

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

Zu verwenden beispielsweise als:

that-script 'ls / /not-here'

Die Idee ist, dass screen mit einer temporären conf-Datei ausgeführt wird, die zwei Bildschirmfenster in einem vertikal geteilten Layout startet. Im ersten führen wir Ihren Befehl mit dem mit dem zweiten verbundenen stderr aus.

Wir verwenden eine benannte Pipe für das zweite Fenster, um dem ersten sein TTY-Gerät mitzuteilen, und auch für das erste, um dem zweiten mitzuteilen, wann der Befehl ausgeführt wurde.

Der andere Vorteil gegenüber Pipe-basierten Ansätzen besteht darin, dass stdout und stderr des Befehls immer noch mit TTY-Geräten verbunden sind, sodass die Pufferung nicht beeinträchtigt wird. Beide Bereiche können auch unabhängig voneinander nach oben und unten gescrollt werden (mithilfe screendes Kopiermodus).

Wenn Sie eine Shell bashinteraktiv mit diesem Skript ausführen, werden Sie feststellen, dass die Eingabeaufforderung im zweiten Fenster angezeigt wird, während die Shell Ihre Eingabe im ersten Fenster liest, da diese Shells ihre Eingabeaufforderung auf stderr ausgeben.

Im Falle von bash, derEchovon dem, was Sie eingeben, wird auch im zweiten Fenster angezeigt, da dasEchowird von der Shell (readline im Fall von bash) auch auf stderr ausgegeben. Bei einigen anderen Shells wie ksh93wird es im ersten Fenster angezeigt (EchoAusgabe durch den Terminalgerätetreiber, nicht durch die Shell), es sei denn, Sie versetzen die Shell mit oder in den emacs- oder vi-Modus .set -o emacsset -o vi

Antwort2

Dies ist eine hässliche Lösung basierend auf dem annotate-outputSkript von DebianANNOTATE-OUTPUT(1). Ich bin nicht sicher, ob das das ist, wonach Sie suchen, aber es könnte ein guter Anfang sein:

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

Sie können es mit ./this_script another_scriptoder testen command.

Antwort3

Ich werde versuchen, den folgenden Teil Ihrer Frage zu analysieren:

würde stattdessen ungefähr so ​​aussehen:

~$ irgendein Befehl
 einige nützliche Ausgabeinformationen |
 mehr Ausgabe | ERROR: ein Fehler
 eine weitere Nachricht | FEHLER: ist aufgetreten
 ~$

Wenn man das, was Sie wollen, aufschlüsseln möchte, wäre das:

1) Der stdoutStream würde nicht jede Zeile mit einem beenden CR LF, sondern mit einem '|'-Zeichen. Dies würde die beiden Streams natürlich nicht aneinander ausrichten, und eine Ausrichtung kommt nicht in Frage, da die Länge zukünftiger Zeilen, die dem hinzugefügt werden, vorhergesagt werden müsste stdout, was natürlich unmöglich ist.

2) Angenommen, wir vergessen die Ausrichtung, würden wir dann einfach das ausgeben, stderrnachdem es von einer Pipeline verarbeitet wurde, die am Anfang jeder Zeile „ERROR:“ hinzufügt. Ich nehme an, das ist ziemlich einfach, indem man ein einfaches Skript erstellt und sicherstellt, dass das stderrimmer durch dieses Skript ausgegeben wird.

Aber das würde eine Ausgabe wie diese erzeugen:

~$ irgendein Befehl
 einige nützliche Ausgabeinformationen|
 mehr Ausgabe| ERROR: ein Fehler
 eine weitere Nachricht| FEHLER: ist aufgetreten

Das ist nicht wirklich hilfreich, oder? Ich glaube auch nicht, dass es das ist, wonach Sie auch suchen!

Das Problem mit der ursprünglichen Frage ist meiner Meinung nach, dass Sie die serielle Natur jeder an einen Stream angehängten Zeile nicht berücksichtigen, im Zusammenhang mit der Tatsache, dass beide Streams asynchron geschrieben werden können.

Ich glaube, die nächstmögliche Lösung wäre die Verwendung von ncurses.
Siehe.
[http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[http://invisible-island.net/ncurses/ncurses-intro.html#updating]

Um das zu tun, was Sie wollen, müssen Sie beide Streams puffern und sie kombinieren, um einen dritten Puffer zu erstellen, der Elemente aus beiden Puffern übernimmt. Dann laden Sie den dritten Puffer in den Terminalbildschirm, indem Sie den Terminalbildschirm löschen und ihn jedes Mal neu zeichnen, wenn sich der dritte Puffer ändert. Aber so ncursesfunktioniert es nun einmal, warum also das Rad neu erfinden und nicht von dort aus weitermachen?
In jedem Fall müssten Sieübernehmen Sie die Art und Weise, wie der Terminal-Bildschirm vollständig gemalt wird! Und richten Sie den Text in der neu gedruckten Version des Bildschirms nach Belieben neu aus. Ähnlich wie bei einem Videospiel mit Terminalzeichen.
Ich hoffe, meine Antwort hilft Ihnen dabei, die Einschränkungen dessen zu verdeutlichen, wonach Sie suchen ...
Entschuldigen Sie, dass ich das wiederhole, aber das größte Problem bei dem, was Sie gezeigt haben, ist, wie der „Prozessor“ der stdoutund stderrStreams die Länge der zukünftigen hinzugefügten Zeilen im Voraus erkennt, um sie richtig auszurichten.

verwandte Informationen