Bash
將數據傳輸到腳本或函式,確定輸出是到 stdout 還是 stderr?
我正在嘗試創建一個通用函式或腳本,我可以將數據通過管道傳輸到其中,並在輸出前添加顯示數據“到達”的 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。