
私は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
~$ |
答え1
screen
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"
たとえば、次のように使用されます。
that-script 'ls / /not-here'
アイデアは、垂直に分割されたレイアウトで2つの画面ウィンドウを起動する一時的なconfファイルで画面を実行することです。最初のコマンドでは、コマンドを実行し、stderrを2番目のコマンドに接続します。
2番目のウィンドウの名前付きパイプを使用して最初のウィンドウとttyデバイスを通信し、最初のウィンドウはコマンドが完了すると2番目のウィンドウに通知します。
パイプベースのアプローチに比べてもう1つの利点は、コマンドのstdoutとstderrがまだttyデバイスに接続されているため、バッファリングに影響を与えないことです。どちらのウィンドウも独立して上下にスクロールできます(コピーscreen
モードを使用)。
このスクリプトを使用してシェルを対話的に実行すると、プロンプトがbash
2番目のウィンドウに表示され、最初のウィンドウに入力した内容がシェルによって読み取られます。なぜなら、このシェルはstderrにプロンプトを出力するからです。
の場合bash
、エコ入力した内容が2番目のウィンドウにも表示されます。エコbash
また、シェルによってstderrに出力されます(この場合はreadline)。たとえば、他のシェルの場合は、最初のウィンドウksh93
に表示されます(エコemacs
シェルを使用したり、シェルをvi
モードに設定したりしない限り、シェルではなくターミナルデバイスドライバによって出力されます。set -o emacs
set -o vi
答え2
annotate-output
Debian スクリプトに基づく醜い解決策は次のとおりです。コメント出力(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
。
答え3
ご質問の次の部分を分析します。
代わりに次のようになります。
~$ いくつかのコマンド 有用な出力情報 追加出力|エラー:エラー その他のメッセージエラーが発生しました。 ~$
誰でも欲しいものを分析するには:
1)stdout
ストリームは各行を「|」で終わらず、代わりに「| CR LF
」文字で終わります。もちろん、これは2つのストリームを一緒に並べ替えるのではなく、追加する将来の行の長さを予測する必要があるため、並べ替えは不可能ですstdout
。もちろんこれは不可能です。 2)ソートを忘れたとし、各行の先頭に「ERROR:」を追加するパイプで処理し、結果を
簡単に出力します。stderr
簡単なスクリプトを作成し、stderr
常にこれを行うと、これを行うのはとても簡単だと思います。
ただし、これにより次の出力が生成されます。
~$ いくつかのコマンド 便利な出力情報| 追加出力|エラー:エラー その他のメッセージエラーが発生しました。
それはあまり役に立ちません、そうですか?私も信じない。あなたも追求するのがこれだ!
元の質問の問題は、2つのストリームが非同期で作成される可能性があるため、ストリームに追加された各行のシリアル属性を考慮しないことです。
最も近い解決策はncurses
.seeを使用することです
。
[http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[http://invisible-island.net/ncurses/ncurses-intro.html#updating]
実行したい操作を実行するには、2つのストリームをバッファリングし、それらを組み合わせて2つのバッファから要素を取得するための3番目のバッファを作成する必要があります。その後、端末画面を消去し、3番目のバッファが変更されるたびに再描画し、3番目のバッファを端末画面にダンプします。しかし、これがうまくいくのですが、ncurses
なぜそこから始めるのではなく、車輪を再発明する必要がありますか?
何があっても必ずやるべきこと端末画面の描画方法を完全に掌握!必要に応じて画面の再印刷バージョンのテキストを並べ替えます。ターミナルキャラクターを持つビデオゲームによく似ています。
私の答えがあなたが求めている限界を明確にするのに役立つことを願っています...繰り返して申し訳ありません。しかし、あなたが示したものの最大の問題は、
ストリームの「プロセッサ」が次の行の長さを事前に知っている方法です。正しく並べ替えるには追加してください。stdout
stderr