2つの別々のストリームにstdoutとstderrを表示する

2つの別々のストリームにstdoutとstderrを表示する

私は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

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

#! /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モードを使用)。

このスクリプトを使用してシェルを対話的に実行すると、プロンプトがbash2番目のウィンドウに表示され、最初のウィンドウに入力した内容がシェルによって読み取られます。なぜなら、このシェルはstderrにプロンプ​​トを出力するからです。

の場合bashエコ入力した内容が2番目のウィンドウにも表示されます。エコbashまた、シェルによってstderrに出力されます(この場合はreadline)。たとえば、他のシェルの場合は、最初のウィンドウksh93に表示されます(エコemacsシェルを使用したり、シェルをviモードに設定したりしない限り、シェルではなくターミナルデバイスドライバによって出力されます。set -o emacsset -o vi

答え2

annotate-outputDebian スクリプトに基づく醜い解決策は次のとおりです。コメント出力(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なぜそこから始めるのではなく、車輪を再発明する必要がありますか?
何があっても必ずやるべきこと端末画面の描画方法を完全に掌握!必要に応じて画面の再印刷バージョンのテキストを並べ替えます。ターミナルキャラクターを持つビデオゲームによく似ています。
私の答えがあなたが求めている限界を明確にするのに役立つことを願っています...繰り返して申し訳ありません。しかし、あなたが示したものの最大の問題は、
ストリームの「プロセッサ」が次の行の長さを事前に知っている方法です。正しく並べ替えるには追加してください。stdoutstderr

関連情報