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

在Bash脚本中,如果出现某种情况,如何退出整个脚本?,bash,scripting,exit,exit-code,Bash,Scripting,Exit,Exit Code,我正在用Bash编写一个脚本来测试一些代码。然而,如果编译代码首先失败,那么运行测试似乎很愚蠢,在这种情况下,我将中止测试 有没有一种方法可以做到这一点,而不用将整个脚本包装在while循环中并使用中断?类似于一个灌木丛灌木丛的话,试试下面这句话: exit 1 用适当的错误代码替换1。另请参见。使用设置-e #!/bin/bash set -e /bin/command-that-fails /bin/command-that-fails2 脚本将在第一行失败后终止(返回非零退出代码)

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

有没有一种方法可以做到这一点,而不用将整个脚本包装在while循环中并使用中断?类似于一个灌木丛灌木丛的话,试试下面这句话:

exit 1

用适当的错误代码替换
1
。另请参见。

使用设置-e

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2
脚本将在第一行失败后终止(返回非零退出代码)。在这种情况下,命令-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
使用集合-e它看起来像:

#!/bin/bash

set -e

cd /project-dir
make

cd /project-dir2
make

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

而不是
If
构造,你可以利用:


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

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

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

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
这些函数是*NIX操作系统和shell风格健壮的。将它们放在脚本(bash或其他)的开头,
try()

解释 (根据评论)

  • yell
    :将脚本名称和所有参数打印到
    stderr
    • $0
      是脚本的路径
    • $*
      都是参数
    • &2
      表示将标准输出重定向到&pipe
      2
      。管道
      1
      将是
      stdout
      本身
  • die
    执行与
    yell
    相同的操作,但退出状态为非0,表示“失败”
  • try
    使用
    |
    (布尔值
    ),它仅在左侧失败时计算右侧。
    • $@
      再次显示所有参数,但是

如果要使用
源调用脚本
,可以使用
返回
,其中
将是脚本退出状态(错误或错误使用非零值)。但是,如果调用可执行脚本(即直接使用其文件名),return语句将导致投诉(错误消息“return:只能从函数或源脚本返回”)

如果改为使用
exit
,则当使用
source
调用脚本时,将导致退出启动脚本的shell,但可执行脚本将按照预期终止

要在同一脚本中处理这两种情况,可以使用

return <x> 2> /dev/null || exit <x>
return 2>/dev/null | |退出
这将处理任何合适的调用。这是假设您将在脚本的顶层使用此语句。我建议不要直接从函数中退出脚本


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

我有同样的问题,但不能问,因为这是一个重复的问题

当脚本稍微复杂一点时,可以接受的答案是使用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
#/bin/bash
(){
为true时;do sleep 1.2;echo boom;done
}
f(){
回声你好
N=0
虽然
((N++5))&退出4#不起作用
((N>5))&&{kill-9$$;退出5;}有效
完成
}
繁荣&
f&
虽然真实;睡眠0.5分钟;回声嘟嘟声;完成

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

使用
set-e
您仍然可以在不停止脚本的情况下使一些命令出错退出:
command 2>&1 | echo$?
如果管道或命令结构返回非零值,则
set-e
将中止脚本。例如,只有当
foo
bar
都返回非零值时,
foo | | bar
才会失败。通常,如果您在开始时添加
set-e
,编写良好的bash脚本将起作用,并且添加作为一种自动的健全性检查:如果出现任何错误,请中止脚本。如果您正在将命令管道连接在一起,通过设置
set-o pipefail
选项,如果其中任何一个失败,您也可以失败。实际上,没有
set-e
的惯用代码只是
make | | exit$?
。您还有
set-u
。看看:
set-euo pipefail
@cmcdragokai,通常任何非零代码都可以工作。如果你不需要什么特别的东西,你可以始终如一地使用
1
。如果脚本将由另一个脚本运行,则可能需要定义自己的一组具有特定含义的状态代码。例如,
1
==测试失败,
2
==编译失败。如果脚本是其他内容的一部分,则可能需要调整代码以匹配其中使用的实践。例如,当automake运行测试套件的一部分时,代码
77
用于标记测试
#!/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