將 stderr 和 stdout 重定向到一個文件會導致錯誤嗎?
我正在編寫一個腳本,它將文件(
filename
…)作為參數,並將 stdout 和 stderr 都重定向到 name 的文件filename.output
。文件中有命令,我只想 bash 一次(以防文件中的命令不應執行多次,即mkdir
或rmdir
)。我發現,在遍歷參數時,此命令有效:bash $a &> "$(basename $a).output"
但是,我還想使用此命令的錯誤狀態,以防
.output
由於某種原因無法創建:if ! bash $a &> "$(basename $a).output" then echo >&2 "failed to create $(basename $a).output" fi
當我這樣做時,我的 if 語句總是評估為 true,我認為這是因為 stdout 或 stderr 需要重定向失敗,而不是它們兩者。我正在測試的命令中很少會同時產生 stderr 和 stdout(即,類似的命令
date
產生 stdout,但沒有 stderr,因此由於 stderr 無法重定向而導致非零返回值)。我對為什麼我的程式碼無法正常執行的分析是否正確,如果是這樣,有沒有辦法單獨檢查 stdout 重定向和 stderr 重定向的失敗,以便我準確地顯示何時
.output
未創建?**編輯:**我發現問題實際上在於
bash "$a"
組件,因為任何時候$a
都是帶有產生錯誤的命令的文件,整個 if 語句的計算結果為真。我想現在我的問題是,是否存在重定向 stdout 和 stderr 會導致我應該注意的錯誤的情況?
如果你這樣做
if ! bash $a &> "$(basename $a).output"; then
如果重定向出錯,或者腳本執行但返回非零退出狀態,則 if 語句的主分支執行。運算符與
&> file
相同> file 2>&1
,它同時重定向 stdout 和 stderr,但由於只涉及一個文件,因此您很難找到一種方法讓其中一個重定向成功,而另一個重定向失敗。重定向可能會失敗,創建文件可能出於各種原因,例如權限問題、不存在的路徑、磁碟已滿。讓我們編寫一個測試腳本:它只會列印一些東西,如果給它一個參數,它會退出並出現錯誤。
$ cat test.sh #!/bin/bash echo test script if [ "$#" != 0 ]; then echo exiting with error exit 1 fi $ chmod +x test.sh
在這裡,重定向失敗(因為
./non-existing-dir/
確實不存在):$ if ! ./test.sh > ./non-existing-dir/test.output; then echo "it failed (for some reason)"; fi bash: ./non-existing-dir/test.output: No such file or directory it failed (for some reason)
在這裡,重定向成功,並將輸出收集到文件中,但腳本本身返回失敗狀態:
$ rm -f test.output $ if ! ./test.sh 1 > ./test.output; then echo "it failed (for some reason)"; fi it failed (for some reason) $ cat test.output test script exiting with error
您不能錯過重定向中的錯誤;一個將導致命令以非零狀態退出。但是確切的值沒有定義並且取決於shell,所以我們不能用它來區分重定向失敗和腳本本身失敗。POSIX Shell 命令語言定義在 2.8.2 命令的退出狀態中說:
如果命令在字擴展或重定向期間失敗,其退出狀態應介於 1 和 125 之間。
Bash 的手冊在3.7.1 Simple Command Expansion中說了類似的話。
現在,如果您確實想專門檢查重定向中的錯誤,您可以這樣做,您只需在執行程序之前單獨打開重定向即可。例如,我們可以使用這樣的腳本來執行我們的程序:
$ cat redir.sh #!/bin/sh outfile="${1?please define output file}" cmd="${2?please define command to run}" shift 2 if ! exec 9> "$outfile"; then echo "error: cannot create redirection to '$outfile'" exit 1 fi if ! "$cmd" "$@" >&9 2>&9; then echo "error: script '$cmd' failed" exit 1 fi exec 9>&- # close the output fd
現在,檢測到失敗的重定向如下:
$ bash redir.sh ./non-existing-dir/test.output ./test.sh redir.sh: line 8: ./non-existing-dir/test.output: No such file or directory error: cannot create redirection to './non-existing-dir/test.output'
腳本也失敗了:
$ bash redir.sh ./test.output ./test.sh 1 error: script './test.sh' failed