在Bash脚本中,如果出现某种情况,如何退出整个脚本?

时间:2009-09-04 09:51:53

标签: bash scripting exit exit-code

我正在用Bash编写一个脚本来测试一些代码。但是,如果首先编译代码失败,运行测试似乎很愚蠢,在这种情况下,我只是中止测试。

有没有办法可以在没有将整个脚本包含在while循环中并使用中断的情况下执行此操作?有点像 dun dun dun goto?

9 个答案:

答案 0 :(得分:633)

试试这句话:

exit 1

1替换为相应的错误代码。另请参阅Exit Codes With Special Meanings

答案 1 :(得分:629)

使用设置-e

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2

脚本将在第一行失败后终止(返回非零退出代码)。在这种情况下, command-that-failed2 将无法运行。

如果要检查每个命令的返回状态,您的脚本将如下所示:

#!/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 ,它看起来像:

#!/bin/bash

set -e

cd /project-dir
make

cd /project-dir2
make

任何失败的命令都会导致整个脚本失败并返回退出状态,您可以使用 $?进行检查。如果您的脚本很长或者您正在构建很多东西,那么如果您在任何地方添加返回状态检查,那将会非常难看。

答案 2 :(得分:183)

一个坏屁股的SysOps家伙曾经教过我三指爪技术:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }

这些功能是* NIX OS和shell风格强大。将它们放在脚本的开头(bash或其他),try()你的陈述和代码。

解释

(基于flying sheep评论)。

  • yell:打印脚本名称和stderr的所有参数:
    • $0是脚本的路径;
    • $*都是参数。
    • >&2表示 >将stdout重定向到&管道2 pipe 1 本身就是stdout
  • dieyell的功能相同,但以非0退出状态退出,即“失败”。
  • try使用||(布尔OR),如果左边没有失败,则仅评估右侧。
    • $@再次是所有参数,但是different

希望能解释一切。

答案 3 :(得分:25)

如果您使用source调用脚本,则可以使用return <x>,其中<x>将是脚本退出状态(使用非零值表示错误或false)。但是如果你调用一个可执行脚本(即直接使用它的文件名),return语句将导致一个抱怨(错误消息&#34; return:只能从函数或源脚本返回&#39;&#34;)

如果使用exit <x>,则使用source调用脚本时,将导致退出启动脚本的shell,但可执行脚本将按预期终止。

要在同一脚本中处理任何一种情况,您可以使用

return <x> 2> /dev/null || exit <x>

这将处理适合的调用。假设您将在脚本的顶级使用此语句。我建议不要直接从函数中退出脚本。

注意:<x>应该只是一个数字。

答案 4 :(得分:10)

我经常包含一个名为run()的函数来处理错误。我想要进行的每个调用都会传递给此函数,以便在发生故障时退出整个脚本。这比set -e解决方案的优势在于,当一行失败时,脚本不会以静默方式退出,并且可以告诉您问题所在。在以下示例中,未执行第3行,因为脚本在调用false时退出。

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"

答案 5 :(得分:5)

您可以利用short-circuit evaluation

代替if构造
#!/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]

注意由于交替运算符的优先级而必需的括号对。 $?是一个特殊变量,用于退出最近调用的命令的代码。

答案 6 :(得分:1)

您可以通过以下方式按程序名称关闭程序:

软退出做

pkill -9 -x programname # Replace "programmname" by your programme

硬退出做

pkill -15 -x programname # Replace "programmname" by your programme

如果您想知道如何评估关闭程序的条件,您需要自定义您的问题。

答案 7 :(得分:0)

我有同样的问题,但不能问,因为它是重复的。

当脚本更加复杂时,使用exit接受的答案不起作用。如果使用后台进程检查条件,则退出仅退出该进程,因为它在子外壳程序中运行。要杀死脚本,必须明确杀死它(至少这是我所知道的唯一方法)。

以下是有关如何执行此操作的小脚本:

#!/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

这是一个更好的答案,但仍然不完整-我真的不知道如何摆脱 boom 部分。

答案 8 :(得分:0)

您可以通过以下方式通过程序的PID关闭程序:

软退出做

kill -9 $PID # Replace "programmname" by your programme

硬退出做

kill -15 $PID # Replace "programmname" by your programme

如果您想知道如何评估关闭程序的条件,您需要自定义您的问题。