簡體   English   中英

如果任何命令返回非零值,則中止 shell 腳本

[英]Aborting a shell script if any command returns a non-zero value

我有一個調用許多命令的 Bash shell 腳本。

如果任何命令返回非零值,我想讓 shell 腳本自動退出,返回值為 1。

如果不明確檢查每個命令的結果,這可能嗎?

例如,

dosomething1
if [[ $? -ne 0 ]]; then
    exit 1
fi

dosomething2
if [[ $? -ne 0 ]]; then
    exit 1
fi

將此添加到腳本的開頭:

set -e

如果一個簡單的命令以非零退出值退出,這將導致 shell 立即退出。 一個簡單的命令是不屬於 if、while 或 until 測試的一部分,或者不屬於 && 或 || 的任何命令列表。

有關更多詳細信息,請參閱“set”內部命令上的bash(1) 手冊頁

我個人以“set -e”開始幾乎所有的 shell 腳本。 當中間出現故障並破壞腳本其余部分的假設時,讓腳本頑固地繼續下去真的很煩人。

添加到接受的答案:

請記住set -e有時是不夠的,特別是如果您有管道。

例如,假設你有這個腳本

#!/bin/bash
set -e 
./configure  > configure.log
make

...按預期工作: configure的錯誤中止執行。

明天你做一個看似微不足道的改變:

#!/bin/bash
set -e 
./configure  | tee configure.log
make

......現在它不起作用。 此處對此進行了解釋,並提供了一種解決方法(僅限 Bash):

#!/bin/bash
set -e 
set -o pipefail

./configure  | tee configure.log
make

您示例中的 if 語句是不必要的。 只需這樣做:

dosomething1 || exit 1

如果您接受 Ville Laurikari 的建議並使用set -e那么對於某些命令,您可能需要使用以下命令:

dosomething || true

|| true 即使命令失敗, || true也會使命令管道具有true返回值,因此-e選項不會終止腳本。

如果您需要在退出時進行清理,您還可以使用帶有偽信號 ERR 的“陷阱”。 這與捕獲 INT 或任何其他信號的工作方式相同; 如果任何命令以非零值退出,bash 將拋出 ERR:

# Create the trap with   
#    trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]
trap "rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM
command1
command2
command3
# Partially turn off the trap.
trap - ERR
# Now a control-C will still cause cleanup, but
# a nonzero exit code won't:
ps aux | grep blahblahblah

或者,特別是如果您使用“set -e”,您可能會陷入 EXIT; 當腳本出於任何原因退出時,您的陷阱將被執行,包括正常結束、中斷、由 -e 選項引起的退出等。

$? 很少需要變量。 偽習語command; if [ $? -eq 0 ]; then X; fi command; if [ $? -eq 0 ]; then X; fi command; if [ $? -eq 0 ]; then X; fi應該總是寫成if command; then X; fi if command; then X; fi if command; then X; fi

$?的情況下$? 當需要針對多個值進行檢查時是必需的:

command
case $? in
  (0) X;;
  (1) Y;;
  (2) Z;;
esac

或者什么時候$? 需要重用或以其他方式操作:

if command; then
  echo "command successful" >&2
else
  ret=$?
  echo "command failed with exit code $ret" >&2
  exit $ret
fi

在頂部使用-eset -e運行它。

也看看set -u

出錯時,以下腳本將打印 RED 錯誤消息並退出。
將其放在 bash 腳本的頂部:

# BASH error handling:
#   exit on command failure
set -e
#   keep track of the last executed command
trap 'LAST_COMMAND=$CURRENT_COMMAND; CURRENT_COMMAND=$BASH_COMMAND' DEBUG
#   on error: print the failed command
trap 'ERROR_CODE=$?; FAILED_COMMAND=$LAST_COMMAND; tput setaf 1; echo "ERROR: command \"$FAILED_COMMAND\" failed with exit code $ERROR_CODE"; put sgr0;' ERR INT TERM
#!/bin/bash -e

應該足夠了。

像這樣的表達

dosomething1 && dosomething2 && dosomething3

當其中一個命令返回非零值時,將停止處理。 例如,以下命令永遠不會打印“done”:

cat nosuchfile && echo "done"
echo $?
1

我只是拋出另一個供參考,因為 Mark Edgars 的輸入還有一個額外的問題,這里是一個額外的例子,涉及整個主題:

[[ `cmd` ]] && echo success_else_silence

cmd || exit errcode相同如某人所示cmd || exit errcode

例如,如果已安裝,我想確保卸載分區:

[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM