Bash

在重定向上附加字元串

  • March 10, 2019

將所有輸出重定向到 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 的方法/技巧來實現。

旁注:testand[是相同的命令,因此您也可以[ "x$foo" = "x" ]在更詳細的 if-else 語句中編寫和使用它

引用自:https://unix.stackexchange.com/questions/505260