為什麼“粘貼”不能在標準錯誤旁邊列印標準輸入?
通常在相鄰列中
paste
列印兩個命名(或等效)文件,如下所示:paste <(printf '%s\n' a b) <(seq 2)
輸出:
a 1 b 2
但是當這兩個文件是
/dev/stdin
and/dev/stderr
時,它的工作方式似乎不同。假設我們有b缺少b框程序,它在標準輸出上輸出兩行,在標準錯誤上輸出兩行。為了說明的目的,這可以用一個函式來模擬:
bb() { seq 2 | tee >(sed 's/^/e/' > /dev/stderr) ; }
現在執行
annotate-output
,(在Debian/Ubuntu/etc.上的**devscripts包中),以顯示它可以工作:annotate-output bash -c 'bb() { seq 2 | tee >(sed 's/^/e/' > /dev/stderr) ; }; bb' 22:06:17 I: Started bash -c bb() { seq 2 | tee >(sed s/^/e/ > /dev/stderr) ; }; bb 22:06:17 O: 1 22:06:17 E: e1 22:06:17 O: 2 22:06:17 E: e2 22:06:17 I: Finished with exitcode 0
所以它有效。餵給:
bb
_paste
bb | paste /dev/stdin /dev/stderr
輸出:
1 e1 e2 ^C
它掛起 -
^C
意味著按Control-C退出。更改
|
為 a;
也不起作用:bb ; paste /dev/stdin /dev/stderr
輸出:
1 2 e1 e2 ^C
也掛起 -
^C
表示按Control-C退出。期望的輸出:
1 e1 2 e2
可以使用
paste
嗎?如果不是,為什麼不呢?
為什麼不能使用 /dev/stderr 作為管道
問題不
paste
在於 ,也不在於/dev/stdin
。它與/dev/stderr
.所有命令都使用一個打開的輸入描述符(0:標準輸入)和兩個輸出(1:標準輸出和 2:標準錯誤)創建。這些通常可以分別使用 names和訪問
/dev/stdin
,但請參閱/dev/stdin、/dev/stdout 和 /dev/stderr 的可移植性如何?. 許多命令,包括,也會將文件名解釋為 STDIN。/dev/stdout``/dev/stderr``paste``-
當您單獨執行
bb
時,STDOUT 和 STDERR 都是控制台,通常會出現命令輸出。這些行通過不同的描述符(如您的 所示annotate-output
)但最終在同一個地方結束。當您添加一個
|
和第二個命令時,創建一個管道……bb | paste /dev/stdin /dev/stderr
|
告訴 shell 將 的輸出連接到bb
的輸入paste
。paste
首先嘗試從 讀取/dev/stdin
,它(通過一些符號連結)解析為它自己的標準輸入描述符(shell 剛剛連接),因此該行1
通過。但是外殼/管道對 STDERR 沒有任何作用。
bb
仍然將(e1
e2
等)發送到控制台。同時,paste
嘗試從掛起的同一個控制台讀取(直到您輸入某些內容)。您的連結為什麼我不能使用文本編輯器閱讀 /dev/stdout?在這裡仍然相關,因為同樣的限制適用於
/dev/stderr
.如何製作第二個管道
您有一個同時產生標準輸出和標準錯誤的命令,並且您希望
paste
這兩行彼此相鄰。這意味著兩個並發管道,每列一個。shell 管道... | ...
提供了其中之一,您需要自己創建第二個,並將 STDERR 重定向到使用2>filename
.mkfifo RHS bb 2>RHS | paste /dev/stdin RHS
如果這是在腳本中使用,您可能更願意在臨時目錄中創建該 FIFO,並在使用後將其刪除。