在重定向上附加字元串
將所有輸出重定向到 stderr 時:
stat file >&2
…如果命令拋出錯誤(例如文件不存在),如何在前面添加一些任意文本,例如:
<<MY ARBITRARY TEXT>>: stat: cannot stat 'file': No such file or directory
需要的邏輯是:
let res = stat file if error then output "<<MY ARBITRARY TEXT>>"+error to stderr else output res to stderr
更多上下文:所有命令輸出都被重定向到 stderr,因為 stdout 和 stderr 流總是以正確的順序返回,即如果發送多個命令並且一個拋出錯誤,則下一個命令的 stdout 可能在原始的 stderr 之前返回命令。為避免這種情況,我將所有命令合併到 stderr,但理想情況下希望能夠輕鬆辨識錯誤。
TL;DR:動態解析 stderr 可能很複雜,因此通過將 stderr 儲存到變數中並稍後操作變數內容來簡化它。
您可能要考慮做的是擷取
stderr
到變數,然後檢查它是否不為空。考慮下面的例子:$ foo=$(stat /etc/passwd 2>&1 > /dev/tty ) File: /etc/passwd Size: 1710 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 537594 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2019-03-08 15:28:10.481688274 -0700 Modify: 2019-03-08 15:28:10.333669255 -0700 Change: 2019-03-08 15:28:10.341670283 -0700 Birth: - $ test "x$foo" = "x" && echo "empty" empty
命令替換
$(...)
執行一個子shell並stdout
僅擷取,因此我們希望將文件描述符1複製到2上2>&1
,以便現在可以通過命令替換擷取stderr,但是我們仍然希望在螢幕上看到正常輸出,因此之後我們指向stdout
控制終端/dev/tty
.現在,如果我們實際上將 stderr 擷取到變數中怎麼辦?
$ foo=$(stat nonexistent.txt 2>&1 > /dev/tty ) $ test "x$foo" = "x" && echo "empty" || echo "not empty" not empty $ printf "<Arbitrary Text>%s\n" "$foo" <Arbitrary Text>stat: cannot stat 'nonexistent.txt': No such file or directory
如您所見,因為
stderr
被擷取,我們可以根據需要將任意文本包裝在它周圍。使用變數的主要原因是標準的 shell 方法(如管道和命令替換)在stdout
文件描述符 1 上執行,因此我們無法stderr
即時解析。當然,我們可以使用命名管道並將其重定向為stat foobar.txt 2> /tmp/named_pipe.fifo
,但這樣做的問題是阻塞 - 發送到管道的資訊會被緩衝,直到被另一個程序使用,因此您的 shell 腳本將被卡住。當然,這可以通過啟動後台程序來處理,但恕我直言,它比必要的複雜性更高,並且使用 Python 這樣的程式語言來執行多個程序要好得多,您實際上可以直接訪問多處理呼叫。如果您希望 stdout 和 stderr 在單獨的變數中進行處理,則 Stack Overflow 上有一個很好的範例,可以通過命名管道以及一些特定於 shell 的方法/技巧來實現。
旁注:
test
and[
是相同的命令,因此您也可以[ "x$foo" = "x" ]
在更詳細的 if-else 語句中編寫和使用它