Bash

將 stderr 和 stdout 重定向到一個文件會導致錯誤嗎?

  • April 13, 2022

我正在編寫一個腳本,它將文件(filename…)作為參數,並將 stdout 和 stderr 都重定向到 name 的文件filename.output。文件中有命令,我只想 bash 一次(以防文件中的命令不應執行多次,即mkdirrmdir)。我發現,在遍歷參數時,此命令有效:

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

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