在兩個單獨的流中顯示 stdout 和 stderr

在兩個單獨的流中顯示 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

您可以使用 GNUscreen的垂直分割功能:

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

這個想法是,它使用一個臨時conf檔案運行螢幕,該檔案以垂直分割佈局啟動兩個螢幕視窗。在第一個中,我們運行您的命令,並將 stderr 連接到第二個。

我們使用第二個視窗的命名管道將其 tty 設備與第一個視窗進行通信,並且第一個視窗在命令完成時通知第二個視窗。

與基於管道的方法相比,另一個優點是命令的 stdout 和 stderr 仍然連接到 tty 設備,因此它不會影響緩衝。兩個窗格也可以獨立地上下滾動(使用 的screen複製模式)。

如果您與該腳本互動地執行 shell bash,您會注意到提示符將顯示在第二個視窗上,而shell 將讀取您在第一個視窗中鍵入的內容,因為這些shell 在stderr 上輸出提示符。

在 的情況下bash迴音您輸入的內容也會顯示在第二個視窗上迴音bash也是由 shell(在 的情況下為 readline)在 stderr 上輸出。對於其他一些 shell,例如ksh93,它將顯示在第一個視窗上(迴音由終端設備驅動程式而不是 shell 輸出),除非您使用or將 shell 置於emacsorvi模式。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而是以「|」結束特點。當然,這不會將兩個流對齊在一起,並且對齊是不可能的,因為它必須預測添加到 的未來行的長度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]

為了完成您要做的事情,您需要緩衝兩個流並將它們組合起來以產生第三個緩衝區,該緩衝區從兩個緩衝區中獲取元素。然後,透過擦除終端螢幕並在每次第三緩衝區發生變化時重新繪製它,將第三緩衝區轉儲到終端螢幕中。但這是有效的方法ncurses,那麼為什麼要重新發明輪子而不是從那裡開始呢?
無論如何,你必須完全接管終端螢幕的繪製方式!並根據需要重新對齊螢幕重印版本中的文字。很像有終端角色的電玩遊戲。
我希望我的回答有助於澄清您所追求的限制...請原諒我重複這一點,但您所展示的最大問題是 和流
的“處理器”如何提前知道 的長度添加未來的線條以便正確對齊它們。stdoutstderr

相關內容