首页 文章

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

提问于
浏览
510

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

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

7 回答

  • 170

    试试这句话:

    exit 1
    

    用适当的错误代码替换 1 . 另见Exit Codes With Special Meanings .

  • 19

    使用 set -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
    

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

  • 550

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

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

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

    解释

    (根据flying sheep评论) .

    • yell :将脚本名称和所有参数打印到 stderr

    • $0 是脚本的路径;

    • $* 都是参数 .

    • >&2 表示 > 将stdout重定向到&pipe 2 . pipe 1 本身就是 stdout .

    • dieyell 相同,但以非0退出状态退出,这意味着“失败” .

    • try 使用 || (布尔值 OR ),如果左侧没有失败,则仅评估右侧 .

    • $@ 再次是所有参数,但different .

    希望能解释一切 .

  • 5

    如果要使用 source 调用脚本,则可以使用 return <x> ,其中 <x> 将是脚本退出状态(对错误使用非零值或为false) . 当您使用脚本时,这也将按预期工作,但如果您调用可执行脚本(即直接使用其文件名),则return语句将导致抱怨(错误消息"return: can only `return' from a function or sourced script") .

    如果使用 exit <x> ,当使用 source 调用脚本时,将导致退出启动脚本的shell,但可执行脚本将直接运行 .

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

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

    这将处理适合的调用 .

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

  • 0

    我经常包含一个名为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"
    
  • 581

    而不是 if 构造,您可以利用short-circuit evaluation

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

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

  • 9

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

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

    这是一个关于如何做的小脚本:

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

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

相关问题