847

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

有没有一种方法可以做到这一点,而无需将整个脚本包装在 while 循环中并使用中断?像dun dun dun goto这样的东西?

4

8 回答 8

989

试试这个说法:

exit 1

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

于 2009-09-04T09:53:53.160 回答
754

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

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

于 2009-09-04T15:18:22.870 回答
282

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

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

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

解释

(基于 飞羊评论)。

  • yell:打印脚本名称和所有参数stderr
    • $0是脚本的路径;
    • $*都是论据。
    • >&2表示>将 stdout 重定向到 & pipe2管道1将是stdout它自己。
  • die与 相同yell,但以非 0 退出状态退出,这意味着“失败”。
  • try使用||(boolean OR),仅在左侧失败时才评估右侧。
    • $@又是所有论点,但不同
于 2014-08-26T21:24:16.767 回答
42

如果您将使用 调用脚本source,则可以使用return <x>where<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>应该只是一个数字。

于 2014-09-12T14:56:31.570 回答
14

我经常包含一个名为 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"
于 2013-09-18T19:21:51.900 回答
7

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]

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

于 2013-09-02T16:52:43.003 回答
2

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

当脚本有点复杂时,使用 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

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

于 2018-10-19T11:24:48.843 回答
1

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

对于软退出做

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

硬退出做

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

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

于 2021-07-07T08:36:31.023 回答