如何擷取修改目前環境的函式的標準錯誤?
Environment Modules 1包的
module
功能通過修改目前shell 程序的各種環境變數來完成它的工作。不幸的是,無論成功與否,這個函式都會返回 0 2,這使得客戶端腳本很難對失敗做出適當的響應。
我想實現一個函式包裝器
mymodule
,module
它將所有參數直接傳遞給,如果失敗module
,則正確返回一個非零值。module
mymodule
可以檢測是否module
失敗的唯一方法是檢查輸出module
函式寫入 stderr(如果有)。問題是我無法想出一個合理的方法
mymodule
來獲得這個輸出而不使module
’ 的動作無效。更具體地說,幾乎所有我能想到的將module
‘stderr 擷取到變數中的方法都需要module
在子程序中執行,從而阻止它完成它的工作(這需要修改目前的 shell)。上述的一個例外是將
module
’s stderr 重定向到一個臨時文件,但我討厭每次module
函式執行時都創建一個文件的想法。有沒有辦法在目前環境
mymodule
中呼叫module
,同時在變數中擷取它的標準錯誤?我對 和 的答案都很
zsh
感興趣bash
。1不要與Lmod 環境模組包混淆,後者俱有非常相似的界面。
2至少對於我必須使用的古老版本 3.2.9 來說是這樣。我無法控制這一點。
Bash 和 zsh 都有協同程序(不幸的是略有不同),它們本質上封裝了一個
pipe
呼叫並產生一個子程序,其標準輸入和標準輸出都可供呼叫 shell 使用。從本質上講,它們讓 shell 在x
和y
中執行x | cmd | y
,但所有x
、y
和都cmd
在目前程序中執行,而不是在管道執行環境中執行。這將讓我們執行
module 2>&...
一些...
,module
從目前 shell 執行。如果我們使用cat
作為我們的協同程序(即cmd
),它只會再次直接重複所有內容,然後我們可以稍後再次將輸出讀回目前 shelly <&...
。另一種選擇是將標準錯誤重定向到另一個後台程序並
wait
為其返回程式碼。我將在下面解決這兩個問題。我將使用這個偽
module
函式進行測試,以便我可以隨意打開和關閉錯誤。if 修改目前的 shell 環境以便我們可以看到它並將“err”輸出到 stderr;我將根據需要評論該行:module() { sleep 1 FOO=$(date) echo err >&2 }
如果我
cat
在 Bash 中執行一個協同程序,我可以將module
’s stderr 重定向到其中,並從cat
’s stdout 讀取以執行我想要的任何操作:coproc cat module 2>&${COPROC[1]} exec {COPROC[1]}>&- if grep -q err <&${COPROC[0]} then echo got an error else echo no error fi
在 zsh 中它需要是
module 2>&p exec 4<&p coproc : if grep -q err <&4
而是在中間。
無論哪種情況,我都可以
module
在目前 shell 中執行命令並從那裡讀取錯誤輸出。函式可以if
正常返回。
cat
除了在目前執行環境中執行之外的所有內容:FD 重定向不會像管道那樣創建獨立的環境。我們可以echo $FOO
在最後檢查一下,並看到日期已經更新,因為module
在目前環境中執行。或者,後台程序可以完成所有工作。這在 Bash 中有效:
exec 2> >( if grep -q . ; then exit 7 ; else exit 0 ; fi ) PID=$! module exec 2>&- wait $PID echo $?
以上將輸出
7
或0
根據頂部子程序所說的內容 - 您可以調整以對返回碼做任何您喜歡的事情。在 zsh 下它沒有,因為$!
沒有為程序替換設置;這應該是可以解決的,但我停止了嘗試。固定的先進先出,而不是臨時文件,也可以在這里工作。在這種情況下,您可能還希望在任一側保存和恢復 FD 2。