linux任何命令返回0,关于linux:如果任何命令返回非零值,则中止shell脚本?

我有一个bash shell脚本,它调用许多命令。如果任何命令返回非零值,我希望shell脚本自动退出,返回值为1。

如果不显式检查每个命令的结果,是否可以这样做?

例如

dosomething1

if [[ $? -ne 0 ]]; then

exit 1

fi

dosomething2

if [[ $? -ne 0 ]]; then

exit 1

fi

除set -e外,还包括set -u或set -eu。-u结束了愚蠢的、隐藏错误的行为,您可以访问任何不存在的变量,并在不进行诊断的情况下生成一个空白值。

将此添加到脚本开头:

set -e

如果一个简单的命令以非零的退出值退出,这将导致shell立即退出。简单命令是不属于if、while或until测试的任何命令,或者是&&或列表的一部分。

有关更多详细信息,请参阅"set"内部命令上的bash(1)手册页。

我个人用"set-e"开始几乎所有shell脚本。当一个脚本在中间发生故障,并且破坏了脚本其余部分的假设时,让它顽固地继续下去,真的很烦人。

那是可行的,但我喜欢用""!/usr/bin/env bash"因为我经常从/bin之外的其他地方运行bash。还有"啊!/usr/bin/env bash-e"不起作用。此外,当我想打开跟踪以进行调试时,最好有一个地方可以修改为"set-xe"。

记住,由于管道的存在,这可能还不够。查看我添加的答案。

此外,如果脚本以bash script.sh的形式运行,则会忽略shebang行上的标志。

只需注意:如果您在bash脚本中声明函数,那么如果您想要扩展这个功能,这些函数需要在函数体中重新声明set-e。

另外,如果你源代码你的脚本,shebang行将是不相关的。

@在bash 3.2.48中似乎没有这种情况。在脚本中尝试以下操作:set -e; tf() { false; }; tf; echo 'still here'。即使没有set -e在tf()体内,执行也会中止。也许你是想说,set -e不是由子类继承的,这是事实。

@Villeraurikari这是为现有的命令,但如何知道手动命令的状态(假设如果我执行了一个程序,如何知道它的状态,不管是成功还是错误)。我有一个场景需要实现,在这里我必须执行n个命令(每个命令都作为线程运行),当其中任何一个失败时,我必须退出脚本。

您也可以稍后在脚本中再次禁用set +e的错误失败。

这是一个很好的答案——但要仔细测试。-e(errexit)在不同版本的bash中是不一致的,除非您非常了解您的脚本,否则您可能会被管道或其他命令中的错误所捕获。您将捕获想要捕获的错误,但在复杂的脚本中,您不会捕获每个错误。

所以脚本中有一些命令即使失败也不会终止脚本。有没有一种方法可以为脚本中有set-e的特定命令设置异常?

要添加到接受的答案中:

记住,有时set -e是不够的,特别是如果你有管道的话。

例如,假设您有这个脚本

#!/bin/bash

set -e

./configure  > configure.log

make

…它按预期工作:configure中的一个错误中止了执行。

明天你会做出一个看似微不足道的改变:

#!/bin/bash

set -e

./configure  | tee configure.log

make

…现在它不起作用了。这里解释了这一点,并提供了一个解决方法(仅限bash):

#!/bin/bash

set -e

set -o pipefail

./configure  | tee configure.log

make

感谢您解释让pipefail与set -o一起使用的重要性!

示例中的if语句是不必要的。就这样做:

dosomething1 || exit 1

如果您采纳Ville Laurikari的建议并使用set -e,那么对于某些命令,您可能需要使用以下命令:

dosomething || true

即使命令失败,|| true也会使命令管道具有true返回值,因此-e选项不会终止脚本。

我喜欢这个。尤其是因为最重要的答案是以bash为中心的(我根本不清楚它是否/在多大程度上适用于zsh脚本)。我可以查一下,但你的逻辑更清楚。

如果您需要在退出时进行清理,也可以将"trap"与伪信号err一起使用。这与补漏白int或任何其他信号的工作方式相同;如果任何命令以非零值退出,bash将抛出err:

# Create the trap with

#    trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]

trap"rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM

command1

command2

command3

# Partially turn off the trap.

trap - ERR

# Now a control-C will still cause cleanup, but

# a nonzero exit code won't:

ps aux | grep blahblahblah

或者,特别是如果您使用的是"set-e",则可以陷阱退出;然后,当脚本出于任何原因退出时,将执行陷阱,包括正常结束、中断、由-e选项引起的退出等。

运行时,-e或set -e位于顶部。

也可以看看set -u。

为了潜在地拯救其他人,需要通读help set:-u将对未设置变量的引用视为错误。

所以要么是set -u要么是set -e,不是两者都是?@蚓糖

@埃里克我几年前退休了。尽管我热爱我的工作,但我年迈的大脑却忘记了一切。我想你可以同时使用这两种语言;我的措辞不好;我应该说"和/或"。

很少需要$?变量。伪成语command; if [ $? -eq 0 ]; then X; fi应该总是写成if command; then X; fi。

需要使用$?的情况是需要对多个值进行检查:

command

case $? in

(0) X;;

(1) Y;;

(2) Z;;

esac

或者当$?需要重新使用或以其他方式操作时:

if command; then

echo"command successful">&2

else

ret=$?

echo"command failed with exit code $ret">&2

exit $ret

fi

为什么"应该总是写为"?我是说,为什么"应该"是这样?当一个命令很长时(考虑使用十几个选项调用gcc),那么在检查返回状态之前运行该命令更容易阅读。

如果命令太长,可以通过命名(定义shell函数)将其分解。

谢谢,正是我要找的…

#!/bin/bash -e

应该足够了。

像这样的表达

dosomething1 && dosomething2 && dosomething3

当其中一个命令返回非零值时将停止处理。例如,以下命令将永远不会打印"完成":

cat nosuchfile && echo"done"

echo $?

1

因为有一个额外的问题要标记Edgars的输入,所以只需插入另一个问题作为参考,这里还有一个额外的示例,并涉及到整个主题:

[[ `cmd` ]] && echo success_else_silence

这和有人展示的cmd || exit errcode是一样的。

我想确保如果安装了分区,就可以卸载它:

[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1

不,[[cmd`]`不是一回事。如果命令的输出为空,则为假;否则为真,无论命令的退出状态如何。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值