在 Bash 脚本中,如果发生某种情况,如何退出整个脚本?
我正在 Bash 中编写一个脚本来测试一些代码。但是,如果编译代码一开始就失败,那么运行测试似乎很愚蠢,在这种情况下我将中止测试。
有没有一种方法可以做到这一点,而无需将整个脚本包装在 while 循环内并使用中断?类似dun dun dun goto 的东西吗?
I'm writing a script in Bash to test some code. However, it seems silly to run the tests if compiling the code fails in the first place, in which case I'll just abort the tests.
Is there a way I can do this without wrapping the entire script inside of a while loop and using breaks? Something like a dun dun dun goto?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
尝试以下语句:
将
1
替换为适当的错误代码。另请参阅具有特殊含义的退出代码。Try this statement:
Replace
1
with appropriate error codes. See also Exit Codes With Special Meanings.使用 set -e
脚本将在第一行失败后终止(返回非零退出代码)。在这种情况下,command-that-fails2 将不会运行。
如果您要检查每个命令的返回状态,您的脚本将如下所示:
使用 set -e 时,它将如下所示:
任何失败的命令都会导致整个脚本失败并返回您可以使用$?检查退出状态。如果你的脚本很长或者你正在构建很多东西,那么如果你到处添加返回状态检查,它会变得非常难看。
Use set -e
The script will terminate after the first line that fails (returns nonzero exit code). In this case, command-that-fails2 will not run.
If you were to check the return status of every single command, your script would look like this:
With set -e it would look like:
Any command that fails will cause the entire script to fail and return an exit status you can check with $?. If your script is very long or you're building a lot of stuff it's going to get pretty ugly if you add return status checks everywhere.
一位 SysOps 人员曾经教过我三指爪技术:
这些功能对于 *NIX 操作系统和 shell 风格来说是稳健的。将它们放在脚本(bash 或其他脚本)的开头,
try()
语句和代码上。解释
(基于飞羊评论)。
yell
:打印脚本名称和所有参数到stderr
:$0
是脚本的路径;$*
都是参数。>&2
表示>
将 stdout 重定向到 &管道2
。 管道1
将是stdout
本身。die
与yell
的作用相同,但以非 0 退出状态退出,这意味着“失败”。try
使用||
(布尔值OR
),如果左侧失败,则仅评估右侧。$@
又是所有参数,但不同。A SysOps guy once taught me the Three-Fingered Claw technique:
These functions are *NIX OS and shell flavor-robust. Put them at the beginning of your script (bash or otherwise),
try()
your statement and code on.Explanation
(based on flying sheep comment).
yell
: print the script name and all arguments tostderr
:$0
is the path to the script ;$*
are all arguments.>&2
means>
redirect stdout to & pipe2
. pipe1
would bestdout
itself.die
does the same asyell
, but exits with a non-0 exit status, which means “fail”.try
uses the||
(booleanOR
), which only evaluates the right side if the left one failed.$@
is all arguments again, but different.如果您将使用
source
调用脚本,则可以使用return
,其中
将是脚本退出状态 (使用非零值表示错误或错误)。但是,如果您调用可执行脚本(即直接使用其文件名),则 return 语句将导致抱怨(错误消息“return:只能从函数或源脚本‘返回’”)。如果使用
exit
来代替,则当使用source
调用脚本时,将导致退出启动该脚本的 shell,但可执行脚本只会终止,如预期的那样。要在同一脚本中处理任一情况,您可以使用
这将处理任何合适的调用。假设您将在脚本的顶层使用此语句。我建议不要直接从函数内退出脚本。
注意:
应该只是一个数字。If you will invoke the script with
source
, you can usereturn <x>
where<x>
will be the script exit status (use a non-zero value for error or false). But if you invoke an executable script (i.e., directly with its filename), the return statement will result in a complain (error message "return: can only `return' from a function or sourced script").If
exit <x>
is used instead, when the script is invoked withsource
, it will result in exiting the shell that started the script, but an executable script will just terminate, as expected.To handle either case in the same script, you can use
This will handle whichever invocation may be suitable. That is assuming you will use this statement at the script's top level. I would advise against directly exiting the script from within a function.
Note:
<x>
is supposed to be just a number.我经常包含一个名为 run() 的函数来处理错误。我想要进行的每个调用都会传递给此函数,以便在发生故障时整个脚本退出。与 set -e 解决方案相比,此解决方案的优点是,当一行失败时,脚本不会静默退出,并且可以告诉您问题是什么。在以下示例中,第 3 行未执行,因为脚本在调用 false 时退出。
I often include a function called run() to handle errors. Every call I want to make is passed to this function so the entire script exits when a failure is hit. The advantage of this over the set -e solution is that the script doesn't exit silently when a line fails, and can tell you what the problem is. In the following example, the 3rd line is not executed because the script exits at the call to false.
您可以利用短路评估if 构造>:
请注意由于交替运算符的优先级而必需的一对括号。
$?
是一个特殊变量,设置为最近调用的命令的退出代码。Instead of
if
construct, you can leverage the short-circuit evaluation:Note the pair of parentheses which is necessary because of priority of alternation operator.
$?
is a special variable set to exit code of most recently called command.说明:
这个问题也是关于如何编写干净的代码。让我们将上面的脚本分为多个部分:
第 1 部分:
exit_trap
是一个在任何步骤失败时调用的函数,并使用$BASH_COMMAND
捕获最后执行的步骤并捕获该步骤的返回代码。这是可用于任何清理的函数,类似于 shutdownhooks文档
第 2 部分:
在 退出信号。
第 3 部分:
如果一系列一个或多个命令返回非零状态,则立即退出。如果失败的命令是紧跟在 while 或until 关键字之后的命令列表的一部分、if 语句中测试的一部分、&& 中执行的任何命令的一部分,则 shell 不会退出。或||列出最后 && 后面的命令除外或 ||,管道中除最后一个命令之外的任何命令,或者命令的返回状态与 ! 反转。如果子 shell 之外的复合命令由于在 -e 被忽略时命令失败而返回非零状态,则 shell 不会退出。如果设置了 ERR 陷阱,则会在 shell 退出之前执行。
文档
第 4 部分:
您可以创建一个
common.sh
文件并在所有脚本中获取它。Explanation:
This question is also about how to write clean code. Let's divide the above script into multiple parts:
Part - 1:
exit_trap
is a function that gets called when any step failed and captures the last executed step using$BASH_COMMAND
and captures the return code of that step. This is the function that can be used for any clean-up, similar to shutdownhooksDoc.
Part - 2:
Register the trap action (here
exit_trap
function) in case of EXIT signal.Part - 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.
Part - 4:
You can create a
common.sh
file and source it in all of your scripts.我有同样的问题,但不能问,因为它会重复。
当脚本稍微复杂一点时,接受的答案(使用 exit)不起作用。如果您使用后台进程来检查条件,则 exit 仅退出该进程,因为它在子 shell 中运行。要终止脚本,您必须显式终止它(至少这是我知道的唯一方法)。
这是一个关于如何执行此操作的小脚本:
这是一个更好的答案,但仍然不完整,我真的不知道如何摆脱 boom 部分。
I have the same question but cannot ask it because it would be a duplicate.
The accepted answer, using exit, does not work when the script is a bit more complicated. If you use a background process to check for the condition, exit only exits that process, as it runs in a sub-shell. To kill the script, you have to explicitly kill it (at least that is the only way I know).
Here is a little script on how to do it:
This is a better answer but still incomplete a I really don't know how to get rid of the boom part.
您可以通过程序名称按照以下方式关闭程序:
对于软退出执行
对于硬退出执行
如果您想知道如何评估关闭程序的条件,您需要自定义您的问题。
You can close your program by program name on follow way:
for soft exit do
for hard exit do
If you like to know how to evaluate condition for closing a program, you need to customize your question.