Bash

將數據傳輸到腳本或函式,確定輸出是到 stdout 還是 stderr?

  • February 28, 2020

我正在嘗試創建一個通用函式或腳本,我可以將數據通過管道傳輸到其中,並在輸出前添加顯示數據“到達”的 fd(stdout 或 stderr)。我的 Bash 技能充其量只是中等水平,而且我發現自己在試圖將我的頭包裹在諸如{ foo 2>&1 >&3 3>&- | bar 3>&-; } 3>&1.

任何人都可以建議這是否可能,以及一種方法嗎?

基本上我想做這樣的事情:

$ { echo "foo" ; echo "bar" 1>&2 ; } | my_output_processor.sh
stdout: foo
stderr: bar 

我已經閱讀了Piping STDERR vs. STDOUT但這並沒有為我解答。我認為https://unix.stackexchange.com/a/440439/307184上的答案可能包含一個線索,但似乎只能在執行腳本中工作,而不是通過管道輸入數據。

我的 Bash 版本在 macOS 上是 5.0。

編輯: @Glenn 下面的回答有效!我做了幾個小幫助函式來節省一些打字和防止錯誤,並像這樣測試:

$ out(){ sed "s/^/out: /" ;} ; err(){ sed "s/^/err: /" 1>&2 ;}
$ { echo "good" ; echo "bad" >&2; } 2> >(err) 1> >(out)
err: bad
out: good

*關於重定向順序的後續問題:*為什麼效果2> >(err) 1> >(out)很好,而1> >(out) 2> >(err)效果不好?(**更新:**下面@RudiC 回答 - 更新了輔助函式,因此它們現在可以按任何順序工作)

使用程序替換而不是管道:

{ echo "foo" ; echo "bar" >&2; } 2> >(sed "s/^/err: /") > >(sed "s/^/out: /")
err: bar
out: foo

如果您在腳本中執行此操作,請使用以下exec命令在腳本的整個持續時間內設置重定向:

bash -c '
   exec 2> >(sed "s/^/err: /") > >(sed "s/^/out: /")
   echo foo
   echo bar >&2
'
err: bar
out: foo

如果你這樣做

exec > >(sed "s/^/out: /") 2> >(sed "s/^/err: /")

那麼輸出是

out: foo
out: err: bar

我認為這就是您所說的“不起作用”。這是因為預設情況下,“err”程序替換的輸出到 stdout,現在指向“out”程序子。你必須這樣做才能繞過它:

exec 3>&1 > >(sed "s/^/out: /") 2> >(sed "s/^/err: /" >&3)

創建另一個指向預設 stdout 的文件描述符 (3),然後 stderr 重定向列印到 fd3。

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