繁体   English   中英

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

[英]In a Bash script, how can I exit the entire script if a certain condition occurs?

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

有没有一种方法可以在不将整个脚本包装在 while 循环中并使用中断的情况下执行此操作? dun dun dun goto 这样的东西?

试试这个语句:

exit 1

1替换为适当的错误代码。 另请参阅具有特殊含义的退出代码

使用设置-e

#!/bin/bash

set -e

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

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

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

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

任何失败的命令都会导致整个脚本失败并返回一个退出状态,您可以使用$? . 如果你的脚本很长或者你正在构建很多东西,如果你在任何地方都添加返回状态检查,它会变得非常丑陋。

一位 SysOps 人员曾教我三指爪技术:

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

这些函数是 *NIX OS 和 shell flavor-robust。 将它们放在脚本的开头(bash 或其他), try()您的语句和代码。

解释

(基于飞羊评论)。

  • yell :打印脚本名称和所有参数到stderr
    • $0是脚本的路径;
    • $*都是参数。
    • >&2表示>将标准输出重定向到 & pipe 2 管道1本身就是stdout
  • dieyell相同,但以非 0 退出状态退出,这意味着“失败”。
  • try使用|| (boolean OR ),如果左侧失败,则仅评估右侧。
    • $@又是所有参数,但不同

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

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

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

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

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

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

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

您可以利用短路评估代替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]

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

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

当脚本有点复杂时,使用 exit 的公认答案不起作用。 如果您使用后台进程来检查条件,则 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

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

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

对于软退出做

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

对于硬退出做

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

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

#!/bin/bash -x

# exit and report the failure if any command fails
exit_trap () {                                         # ---- (1)
  local lc="$BASH_COMMAND" rc=$?
  echo "Command [$lc] exited with code [$rc]"
}

trap exit_trap EXIT                                    # ---- (2)

set -e                                                 # ---- (3)

解释:

这个问题也是关于如何编写干净的代码。 让我们将上面的脚本分成多个部分:


第 1 部分: exit_trap是一个函数,它在任何步骤失败时被调用并使用$BASH_COMMAND捕获最后执行的步骤并捕获该步骤的返回代码。 这是可以用于任何清理的功能,类似于shutdownhooks

当前正在执行或将要执行的命令,除非 shell 正在执行命令作为陷阱的结果,在这种情况下,它是在陷阱时执行的命令。

医生。


第2部分:

trap [action] [signal]

EXIT 信号的情况下注册陷阱操作(此处exit_trap函数)。


第 3 部分:

如果一个或多个命令的序列返回非零状态,则立即退出。 如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、if 语句中测试的一部分、&& 或 || 中执行的任何命令的一部分,则 shell 不会退出。 列出除最后一个 && 或 || 之后的命令之外的命令,管道中除最后一个命令之外的任何命令,或者如果命令的返回状态被反转。,如果子 shell 以外的复合命令返回非零状态,因为命令在忽略 -e 时失败。 shell 不退出,ERR 上的陷阱(如果已设置)。 在 shell 退出之前执行。

医生。


第 4 部分:

您可以创建一个common.sh文件并在所有脚本中获取它。

source common.sh

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM