In a Bash script, how can I exit the entire script if a certain condition occurs?
我正在用Bash编写一个脚本来测试一些代码。 但是,如果首先编译代码失败,运行测试似乎很愚蠢,在这种情况下,我只是中止测试。
有没有办法可以在没有将整个脚本包含在while循环中并使用中断的情况下执行此操作? 有点像dun dun dun goto?
试试这句话:
1 | exit 1 |
用适当的错误代码替换
使用set -e
1 2 3 4 5 6 | #!/bin/bash set -e /bin/command-that-fails /bin/command-that-fails2 |
脚本将在第一行失败后终止(返回非零退出代码)。在这种情况下,command-that-failed2将不会运行。
如果要检查每个命令的返回状态,则脚本将如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/bin/bash # I'm assuming you're using make cd /project-dir make if [[ $? -ne 0 ]] ; then exit 1 fi cd /project-dir2 make if [[ $? -ne 0 ]] ; then exit 1 fi |
使用set -e,它看起来像:
1 2 3 4 5 6 7 8 9 | #!/bin/bash set -e cd /project-dir make cd /project-dir2 make |
任何失败的命令都会导致整个脚本失败并返回退出状态,您可以使用$?进行检查。如果您的脚本很长或者您正在构建很多东西,那么如果您在任何地方添加返回状态检查,那将会非常难看。
一个坏屁股的SysOps家伙曾经教过我三指爪技术:
1 2 3 | yell() { echo"$0: $*">&2; } die() { yell"$*"; exit 111; } try() {"$@" || die"cannot $*"; } |
这些功能是* NIX OS和shell风格强大。将它们放在脚本的开头(bash或其他),
说明
(根据飞羊评论)。
-
yell :将脚本名称和所有参数打印到stderr :-
$0 是脚本的路径; -
$* 都是参数。 -
>&2 表示> 将stdout重定向到&pipe2 。 pipe1 本身就是stdout 。
-
-
die 与yell 相同,但以非0退出状态退出,这意味着"失败"。 -
try 使用|| (布尔OR ),如果左侧失败,则仅评估右侧。-
$@ 是所有参数,但不同。
-
如果要使用
如果使用
要在同一脚本中处理任何一种情况,您都可以使用
1 | return <x> 2> /dev/null || exit <x> |
这将处理适合的调用。假设您将在脚本的顶层使用此语句。我建议不要直接从函数中退出脚本。
注意:
我经常包含一个名为run()的函数来处理错误。我想要进行的每个调用都会传递给此函数,以便在发生故障时退出整个脚本。这比set -e解决方案的优势在于,当一行失败时,脚本不会以静默方式退出,并且可以告诉您问题所在。在以下示例中,未执行第3行,因为脚本在调用false时退出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function run() { cmd_output=$(eval $1) return_value=$? if [ $return_value != 0 ]; then echo"Command $1 failed" exit -1 else echo"output: $cmd_output" echo"Command succeeded." fi return $return_value } run"date" run"false" run"date" |
您可以利用短路评估来代替
1 2 3 4 5 6 7 | #!/usr/bin/env bash echo $[1+1] echo $[2/0] # division by 0 but execution of script proceeds echo $[3+1] (echo $[4/0]) || exit $? # script halted with code 1 returned from `echo` echo $[5+1] |
注意由于交替运算符的优先级而必需的括号对。
我有同样的问题,但不能问它,因为它会是重复的。
使用exit时接受的答案在脚本稍微复杂时不起作用。如果使用后台进程检查条件,则退出仅退出该进程,因为它在子shell中运行。要杀死脚本,你必须明确地杀死它(至少这是我所知道的唯一方法)。
这是一个关于如何做的小脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/bin/bash boom() { while true; do sleep 1.2; echo boom; done } f() { echo Hello N=0 while ((N++ <10)) do sleep 1 echo $N # ((N > 5)) && exit 4 # does not work ((N > 5)) && { kill -9 $$; exit 5; } # works done } boom & f & while true; do sleep 0.5; echo beep; done |
这是一个更好的答案,但仍然不完整,我真的不知道如何摆脱繁荣部分。