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

有没有一种方法,我可以这样做,而不包装整个脚本在一个while循环和使用中断?像是叮叮当当的后藤?


当前回答

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

解释:

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


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

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

Doc.


第二部分:

trap [action] [signal]

在出现EXIT信号时注册trap动作(这里是exit_trap函数)。


第3部分:

Exit immediately if a sequence of one or more commands returns a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits.

Doc.


第4部分:

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

source common.sh

其他回答

而不是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 1

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

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

任何失败的命令都将导致整个脚本失败,并返回一个退出状态,您可以使用$?如果你的脚本很长,或者你构建了很多东西,如果你到处添加返回状态检查,那就会很难看。

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

解释:

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


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

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

Doc.


第二部分:

trap [action] [signal]

在出现EXIT信号时注册trap动作(这里是exit_trap函数)。


第3部分:

Exit immediately if a sequence of one or more commands returns a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits.

Doc.


第4部分:

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

source common.sh

一个SysOps的人曾经教过我三指爪技术:

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

这些函数是*NIX OS和shell风味健壮的。把它们放在脚本的开头(bash或其他),try()你的语句和代码。

解释

(根据飞行绵羊的评论)。

大喊:打印脚本名称和所有参数到stderr: $0是脚本的路径; $*都是参数。 >&2表示>将标准输出重定向到&管道2。管道1本身就是标准输出。 Die的作用与yell相同,但是以非0的退出状态退出,这意味着“失败”。 try使用||(布尔OR),如果左边失败,它只计算右边。 $@又是所有的参数,但有所不同。