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

sam*_*moz 641 bash scripting exit-code exit

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

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

Mic*_*kis 725

试试这句话:

exit 1
Run Code Online (Sandbox Code Playgroud)

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

  • 不,这也会关闭窗口,而不仅仅是退出脚本 (13认同)
  • @ToniLeigh `exit` 命令仅退出脚本正在运行的 bash 进程。如果您使用 `./script.sh` 或 `bash script.sh` 运行脚本,您的“窗口”或 shell 将保持打开状态,因为为该脚本创建一个新的 bash 进程。另一方面,如果您使用 `. script.sh` 或 `source script.sh`,它在当前的 bash 实例中执行并退出它。 (7认同)
  • @ToniLeigh如果它关闭“窗口”,您可能会将“exit #”命令放入函数中,而不是脚本中。(在这种情况下,请使用“return #”。) (6认同)
  • @ToniLeigh bash没有"窗口"的概念,你可能会对你的特定设置(例如终端模拟器)做什么感到困惑. (5认同)
  • @MichałGórny什么是好的状态代码? (4认同)
  • @CMCDragonkai,通常任何非零代码都可以.如果你不需要任何特殊的东西,你可以一致地使用`1`.如果脚本要由另一个脚本运行,您可能需要定义自己的一组具有特定含义的状态代码.例如,`1` ==测试失败,`2` ==编译失败.如果脚本是其他内容的一部分,您可能需要调整代码以匹配其中使用的实践.例如,当部分测试套件由automake运行时,代码"77"用于标记跳过的测试. (4认同)

Shi*_*zmo 660

使用set -e

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2
Run Code Online (Sandbox Code Playgroud)

脚本将在第一行失败后终止(返回非零退出代码).在这种情况下,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
Run Code Online (Sandbox Code Playgroud)

使用set -e,它看起来像:

#!/bin/bash

set -e

cd /project-dir
make

cd /project-dir2
make
Run Code Online (Sandbox Code Playgroud)

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

  • 实际上没有`set -e`的惯用代码就是`make || 退出$?`. (18认同)
  • 使用`set -e`你仍然可以*make*some*命令在不停止脚本的情况下退出:`command 2>&1 || echo $?`. (9认同)
  • 如果您正在将命令组合在一起,那么如果通过设置`set -o pipefail`选项失败它们也会失败. (5认同)
  • 如果管道或命令结构返回非零值,`set -e`将中止脚本.例如`foo || 只有当`foo`和`bar`都返回非零值时,bar`才会失败.通常,如果在开始时添加`set -e`并且添加作为自动完整性检查工作,那么编写良好的bash脚本将起作用:如果出现任何问题,则中止脚本. (4认同)
  • 你也有`set -u`.看看[unofficial**bash strict mode**](http://redsymbol.net/articles/unofficial-bash-strict-mode/):`set -euo pipefail`. (2认同)

c.g*_*rez 212

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

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

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

说明

(根据 飞羊评论).

  • yell:打印脚本名称和所有参数stderr:
    • $0 是脚本的路径;
    • $* 都是争论.
    • >&2意味着>将stdout重定向到&pipe2.1stdout本身.
  • die做同样的yell,但以非0退出状态退出,这意味着"失败".
  • try使用||(布尔值OR),如果左边没有失败,它只评估右侧.
    • $@是所有的争论,但不同.

希望能解释一切.

  • **大叫**:`$ 0`是脚本的路径.`$*`都是参数.`>&2`表示"`>`将stdout重定向到`&`pipe`2`".管道1本身就是stdout.所以**yell**使用脚本名称为所有参数添加前缀并打印到stderr.**die**与**yell**相同​​,但以非0退出状态退出,这意味着"失败".**try**使用布尔值或`||`,如果左侧没有失败,它只评估右侧.`$ @`是所有参数,但[不同](http://stackoverflow.com/questions/9915610/the-difference-between-and).希望能解释一切 (14认同)
  • @TheJavaGuy-IvanMilosavljević 一旦将这三行添加到脚本顶部,您就可以开始在代码中使用“try”函数。例如:`尝试 cp ./fake.txt ./copy.txt` (4认同)
  • 我是unix脚本的新手.你能解释一下如何执行上述功能吗?我看到了一些我不熟悉的新语法.谢谢. (3认同)
  • 我可以看到我将如何使用 `yell` 和 `die`。然而,`try` 不是那么多。你能提供一个你使用它的例子吗? (3认同)
  • 嗯,但是如何在脚本中使用它们呢?我不明白你所说的“try() 你的声明和代码”是什么意思。 (2认同)

kav*_*ias 29

如果您将调用脚本source,您可以使用return <x>其中<x>将脚本退出状态(使用一个非零值的错误或虚假).当您exit <x>使用脚本时,这也将按预期工作,但如果您调用可执行脚本(即直接使用其文件名),则返回语句将导致抱怨(错误消息"返回:只能从函数返回'或源脚本").

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

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

return <x> 2> /dev/null || exit <x>
Run Code Online (Sandbox Code Playgroud)

这将处理适合的调用.

注意:source应该只是一个数字.


Jos*_*edy 11

我经常包含一个名为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"
Run Code Online (Sandbox Code Playgroud)


ska*_*lee 5

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]
Run Code Online (Sandbox Code Playgroud)

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

  • @Anentropic @skalee括号与优先级无关,但与异常处理无关。除零将导致立即退出具有代码1的shell。如果没有括号(即简单的`echo $ [4/0] || exit $?`),_ bash_将永远不会执行`echo`,更不用说服从“ ||”了。 (2认同)