
我有一個 bash 腳本,它使用set -o errexit
以便在出錯時整個腳本在失敗時退出。
該腳本運行的curl
命令有時無法檢索預期的檔案 - 但是當發生這種情況時,腳本不會錯誤退出。
我已經添加了一個for
循環
- 暫停幾秒鐘,然後重試該
curl
命令 - 在 for 迴圈的底部使用
false
來定義預設的非零退出狀態 - 如果curl 指令成功 - 迴圈將中斷且最後一個指令的退出狀態應為零。
#! /bin/bash
set -o errexit
# ...
for (( i=1; i<5; i++ ))
do
echo "attempt number: "$i
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
if [ -f ~/.vim/autoload/pathogen.vim ]
then
echo "file has been retrieved by curl, so breaking now..."
break;
fi
echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
sleep 5
# exit with non-zero status so main script will errexit
false
done
# rest of script .....
問題是當curl
命令失敗時,循環會重試該命令五次 - 如果所有嘗試均不成功,則 for 循環結束並且主腳本恢復 - 而不是觸發errexit
.
如果此語句失敗,如何讓整個腳本退出curl
?
答案1
代替:
done
和:
done || exit 1
for
如果循環以非零退出程式碼退出,這將導致程式碼退出。
順便說一下,不需要1
in 。如果下載失敗,exit 1
普通exit
命令將以最後執行的命令的退出狀態退出,該狀態將為(code=1)。false
如果下載成功,循環的退出代碼就是echo
指令的退出代碼。 echo
通常以 code=0 退出,表示成功。在這種情況下,||
不會觸發並且exit
不會執行該命令。
最後,請注意,這set -o errexit
可能充滿驚喜。有關其優缺點的討論,請參閱格雷格的常見問題 #105。
文件
從man bash
:
為了(( 表達式 1 ; 表達式 2 ; 表達式 3 )) ;做列表 ; 完畢
首先,算術表達式 expr1 根據下方算術求值中所描述的規則求值。然後重複計算算術表達式 expr2,直到計算結果為零。每次 expr2 計算結果為非零值時,都會執行 list 並計算算術表達式 expr3。如果省略任何表達式,則其計算結果就像是 1。 傳回值是清單中執行的最後一個命令的退出狀態,如果任何表達式無效,則傳回 false。[強調已添加]
答案2
如果您希望在第一次失敗時停止循環,並避免set -e
,您可以執行以下操作:
for i in `seq 1 10`; do
run_command || exit 1;
done
答案3
如果您已errexit
設置,則該false
語句應導致腳本立即退出。如果curl
命令失敗,同樣的情況。
您的範例腳本,如所寫,如果設定了 errexit,則應curl
在第一次呼叫時在第一個命令失敗後退出。false
要查看它是如何工作的(我使用簡寫-e
來設定errexit
:
$ ( set -e; false; echo still here )
$
$ ( set +e; false; echo still here )
still here
$
因此,如果該curl
命令執行多次,則該腳本沒有errexit
設定。
答案4
set -o errexit
在循環和子 shell 中可能會很棘手,因為您必須從進程中返回。
打破循環(即使在正常操作中)被認為是不好的做法。你可以說我是老派,在兩個條件下更喜歡 while 循環而不是 for 循環,但我發現讀起來更好:
i=1
RET=-1
while [ $i -le 5 ] && [ $RET -ne 0 ]; do
[ $i -eq 1 ] || sleep 5
echo "attempt number: "$i
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
RET=$?
i=$((i+1))
done
exit $RET