我正在尋找一種在視覺上分離 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 置於emacs
orvi
模式。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
而是以「|」結束特點。當然,這不會將兩個流對齊在一起,並且對齊是不可能的,因為它必須預測添加到 的未來行的長度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
,那麼為什麼要重新發明輪子而不是從那裡開始呢?
無論如何,你必須完全接管終端螢幕的繪製方式!並根據需要重新對齊螢幕重印版本中的文字。很像有終端角色的電玩遊戲。
我希望我的回答有助於澄清您所追求的限制...請原諒我重複這一點,但您所展示的最大問題是 和流
的“處理器”如何提前知道 的長度添加未來的線條以便正確對齊它們。stdout
stderr