2つの別々のストリームで標準出力と標準エラー出力を表示する


12

私は、stdoutとstderrを視覚的に分離して、インターリーブしないようにし、簡単に識別できるようにする方法を探しています。理想的には、stdoutとstderrには、画面上に、たとえば異なる列に表示される別々の領域があります。たとえば、次のような出力になります。

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

代わりに次のようになります。

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


その質問は同じことを尋ねているようには見えず、答えはどれもここで尋ねられたものを提供しません。
マイケルホーマー

2
ストリームを2つの異なるログファイルにリダイレクトしてから、それらにMultiTailなどを使用すると便利ですか?vanheusden.com/multitail
Kusalananda

annotate-outputユーティリティは便利に見えますか、または列の出力が必要ですか?
ジェフシャラー

回答:


4

GNU screenの垂直分割機能を使用できます。

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

たとえば次のように使用するには:

that-script 'ls / /not-here'

アイデアは、垂直分割レイアウトで2つの画面ウィンドウを開始する一時的なconfファイルで画面を実行することです。最初のコマンドでは、2番目のコマンドにstderrを接続してコマンドを実行します。

2番目のウィンドウに名前付きパイプを使用して、ttyデバイスを最初のウィンドウに通信し、最初のウィンドウにコマンドが完了したときに2番目のウィンドウを通知します。

パイプベースのアプローチと比較した他の利点は、コマンドのstdoutとstderrがまだttyデバイスに接続されているため、バッファリングに影響しないことです。両方のペインを個別に上下にスクロールすることもできます(screenのコピーモードを使用)。

bashそのスクリプトでインタラクティブにシェルを実行すると、2番目のウィンドウにプロンプ​​トが表示され、シェルがstderrにプロンプ​​トを出力するときに最初のウィンドウに入力した内容が読み取られます。

以下の場合にはbashエコー、あなたもそのように第二のウィンドウに表示される入力内容のエコー(の場合はreadlineのシェルによって出力されるbashstderrに)も。以下のようないくつかの他のシェルではksh93、それは最初のウィンドウ(に表示されますエコーあなたがシェルを入れない限り、ターミナルデバイスドライバではなく、シェルによって出力)emacsまたはviでモードset -o emacsset -o vi


1

これはannotate-outputDebian ANNOTATE-OUTPUT(1)のスクリプトに基づいたい解決策です。これがあなたが探しているものであるかどうかはわかりませんが、最初に何かすることができます:

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

./this_script another_scriptまたはを使用してテストできcommandます。


1

私はあなたの質問の次の部分を分析しようとします:

代わりに次のようになります。

 〜$コマンド
 有用な出力情報|
 より多くの出力| エラー:エラー
 別のメッセージ| エラー:が発生しました
 〜$ 

あなたが望むものを分解したい場合は、次のとおりです:

1)stdoutストリームは各行をCR LF「|」で終了せずに終了します キャラクター。もちろん、2つのストリームを一緒に整列させることはstdoutできません。また、に追加される将来の行の長さを予測する必要があるため、整列は問題外です。

2)アライメントを忘れると仮定するとstderr、各行の先頭に「ERROR:」を追加するパイプラインによって処理された後、単に出力します。これは簡単なスクリプトを作成することで非常に簡単になり、stderr常にこのスクリプトを介して出力されることを確認します。

ただし、次のような出力が作成されます。

〜$コマンド
 いくつかの有用な出力情報|
 より多くの出力| エラー:エラー
 別のメッセージ| エラー:が発生しました

本当に役に立たないのはどれですか?また、私は信じていません、それはあなたが何であるかです!

最初の質問の問題は、両方のストリームが非同期に書き込まれる可能性があるという事実に関連して、ストリームに追加される各行のシリアルの性質を考慮していないことだと思います。

最も近い解決策は使用することだと思いますncurses
見る。
[ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[ http://invisible-island.net/ncurses/ncurses-intro.html#updating]

両方のストリームをバッファリングし、それらを結合して、両方のバッファから要素を取得する3番目のバッファを生成する必要がある後、あなたがしていることをするために。次に、3番目のバッファが変更されるたびに、端末画面を消去して再描画することにより、3番目のバッファを端末画面にダンプします。しかし、これが機能する方法なncursesので、なぜ車輪を再発明してそこから取り上げないのでしょうか?
いずれにしても、ターミナル画面が完全にペイントされる方法引き継ぐ必要があります!そして、好きなように画面の再印刷バージョンのテキストを再配置します。ターミナルキャラクターを使用したビデオゲームによく似ています。
私の答えが、あなたが求めているものの限界を明確にするのに役立つことを願っています...
「プロセッサ」でしょうどのように示したものと本が、最大の問題を繰り返すすみませんがあるstdoutstderrストリームは、事前に適切に整合させるためには、それに付加将来のラインの長さを知っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.