Bash

當第一個腳本中呼叫的腳本以錯誤程式碼退出時,如何繼續執行腳本?

  • November 24, 2020

我正在嘗試編寫一個 bash 腳本,該腳本將重複執行第二個腳本,直到它失敗並擷取第二個腳本的標準輸出和標準錯誤。我已經設法處理了這個過程中遇到的大多數問題,並最終得到了這個腳本(稱為error_checker.sh):

#!/usr/bin/env bash

i=0

while [ $? -ne 1 ]
do
i=$[$i+1]
source script.sh &> log.txt
echo "This error occurred after $i run(s)." >> log.txt
done

我想重複重複的腳本被稱為script.sh,並且具有以下程式碼:

#!/usr/bin/env bash

n=$(( RANDOM % 100 ))

if [[ n -eq 42 ]]; then
   echo "Something went wrong"
   >&2 echo "The error was using magic numbers"
   exit 1
fi

echo "Everything went according to plan"

error_checker.sh腳本可以將失敗執行的 stdout 和 stderr 輸出到指定文件 log.txt,但隨著該腳本與該行的第二個腳本一起退出

source script.sh &> log.txt

因此,我無法將其他錯誤消息附加到該文件。

我已經搜尋了一段時間,發現這可能與執行第二個腳本時創建子shell有關,這可能會解決問題,但我只是無法讓腳本執行使用./而不是source. 如果我更改source./,當我輸入 時,整個終端就會凍結./error_checker.sh

非常感謝任何幫助!

更新: 感謝目前的答案!我認為現在我的主要問題是,當我更改source script.sh./script.sherror_checker.sh新的 shell 程序中執行它時,整個終端都凍結了,這使我無法使用./. 這就是為什麼我只能error_checker.sh在使用source script.sh. 任何想法發生了什麼?

更新二: 我改source./,發現雖然整個終端好像當機了,我不得不按ctrl+c來結束程序,它仍然可以生成一個log.txt。但是,雖然 using 的版本source會生成一個 log.txt Something went wrong. The error was using magic numbers,這表明 stdout 和 stderr 是由 using 擷取的&>,但 using 的版本會./生成一個 log.txt 的說法 Everything went according to plan. The error occurred after X run(s)。知道發生了什麼嗎?

最後更新:我已經根據 Glenn 對以下內容的回答編輯了我的程式碼,它執行良好。似乎 while 循環中的 echo 命令阻止了我實際評估 script.ph 的退出狀態,從而創建了一個無限循環。

#!/usr/bin/env bash

i=0

while [ $? -ne 1 ]
do
((i++))
./script.sh >& log.txt
done

echo "This error occurred after $i run(s)." >> log.txt

因為您正在採購腳本,所以更改exit 1return 1

如果您還計劃將 script.sh 作為“頂級”腳本執行,您可以執行

if (( n == 42 )); then
   if [[ "$0" == "${BASH_SOURCE[0]}" ]]; then
       # I'm the "main" script
       exit 1
   else
       # I'm being sourced from some other script
       return 1
   fi
fi

如果您必須使用source(我對此表示懷疑,但我們必須查看程式碼)並且您無法更改該腳本,那麼您必須在子 shell 中執行 source 命令。這意味著exit將退出子shell,而不是執行頂層程序的目前shell:

i=0
#     /--------------------------------\  parentheses create a subshell
while (source script.sh >> log.txt 2>&1)
do
   ((i++))
done
echo "This error occurred after $i run(s)." >> log.txt

這將創建一個日誌文件,其中包含:

Everything went according to plan
...
Everything went according to plan
Something went wrong
The error was using magic numbers
This error occurred after 302 run(s).

關於您的程式碼的一些註釋:

  • $[...]是未記錄的語法,可能已棄用。用於$((...))算術擴展或((...))算術評估。
  • $?前一個命令的退出狀態,對於 while 循環的第二次迭代,它是echo. 由於echo僅在無法寫入標準輸出(或指定的文件描述符)時返回非零,因此您有一個無限循環*,因為您沒有測試 script.sh 的退出狀態!*
    • 在出現錯誤情況後,您有大約 100 分之一的機會按下 Ctrl+C,因此 99% 的時間日誌文件將包含“好”消息”
  • &>不是慣用語:使用>& file或更明顯的>file 2>&1.
  • 您很可能希望在循環外列印“錯誤發生在…之後”消息

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