我正在使用以下选项
set -o pipefail
set -e
在Bash脚本中停止错误执行。我有大约100行要执行的脚本,不想检查每一行脚本的返回代码。
但是对于一个特定的命令,我希望忽略错误。我该怎么办?
particular_script || true
示例:
$ cat /tmp/1.sh
particular_script()
{
false
}
set -e
echo one
particular_script || true
echo two
particular_script
echo three
$ bash /tmp/1.sh
one
two
three
永远不会被打印出来。
另外,我想补充一点,当pipefail
开启时,
如果管道中的某个命令退出状态为非零(在关闭pipefail
时必须是最后一个命令),那么Shell就认为整个管道的退出状态为非零。
$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0
在您希望忽略错误的命令后添加|| true
即可。
set -e
并尝试捕获错误消息时,这一点非常重要,例如:set -e; TEST=$(foo 2>&1 || true); echo $TEST
。 - Spankyset -e
,将bash命令未找到的错误重定向到了$TEST
。这样怎么能保留响应代码呢? - CervEdset -e; TEST=$(foo 2>&1) || printf "ERROR $?: $TEST\n"
- CervEd不要停止并保存退出状态
如果你希望你的脚本在特定命令失败时不停止,并且还希望保存失败命令的错误码:
set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE
command
就成功了,所以需要运行 ||
后面的内容。读作:如果 command
失败,则执行 EXIT_CODE=$?
。你可能只需执行 command || echo "$?"
或使用 "trap" 进行更详细的调试。参见此处 -> https://dev59.com/0m025IYBdhLWcg3wRTtK#6110446 - tinnickset -e
命令会关闭 SSH 会话。 - alper更简洁地说:
! particular_script
根据POSIX规范中关于set -e
的说明(重点是我的):
当打开此选项时,如果一个简单命令因Shell错误的某些原因失败或返回一个大于0的退出状态值,并且不是while、until或if关键字后紧随的复合列表的一部分,并且不是AND或OR列表的一部分,并且不是由"!"保留字引导的管道,则shell应立即退出。
particular_script
的返回值,但如果particular_script
是一个函数,我就不想忽略函数内部语句的返回值。||
解决方案将忽略particular_script
函数体内的所有返回代码,这通常不是您想要的(https://dev59.com/xWIj5IYBdhLWcg3w4Y2S#37191242)。 - Johannes||
无法使用,但是这个可以。谢谢! - bernstein与其“返回true”,您还可以使用“noop”或null实用程序(如POSIX规范中所述):
,仅仅是“什么都不做”。这样可以节省几个字符。 :)
#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."
alias null=:
,如果你觉得更清晰,你可以使用null
代替:
。 - Timonull
代替:
可能会更熟悉/自然于其他语言的开发人员,但这在shell脚本中并不正确。Shell脚本实际上并没有返回任何东西(除了错误号码或成功的0),也没有null
这样的类型。添加这样的别名可能会让未来的开发人员误入歧途,因为他们可能会想做类似于alias null=:; if [[ null != $nonexistentghing ]]; then echo "It's set! (not really)"; fi
这样的事情,但这根本不是shell的工作方式。 - Timo我找到了另一种解决方法:
set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e
你可以通过 set +e
关闭错误时的失败情况,这将忽略该行后的所有错误。完成后,如果想要脚本在任何错误时再次失败,可以使用 set -e
。
应用 set +e
后,当找不到文件时,find
不再使整个脚本失败。同时,find
的错误消息仍然会被打印出来,但整个脚本会继续执行。所以如果这导致问题,很容易进行调试。
这对于 CI 和 CD 非常有用(例如在 GitHub Actions 中)。
感谢上面提供的简单解决方案:
<particular_script/command> || true
以下结构可用于脚本步骤的附加操作/故障排除和附加流程控制选项:
if <particular_script/command>
then
echo "<particular_script/command> is fine!"
else
echo "<particular_script/command> failed!"
#exit 1
fi
如果需要,我们可以通过exit 1
来停止进一步的操作。
如果你想防止你的脚本失败并且收集返回码:
command () {
return 1 # or 0 for success
}
set -e
command && returncode=$? || returncode=$?
echo $returncode
无论命令成功或失败,returncode
都会被收集。
command && exit $? || exit $?
也可以达到同样的效果,但实际上command; exit
也可以。 - tripleeeoutput=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status
log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
if [ "$exit_status" = 0 ]
then
event="$output"
log_event
else
event="ERROR $output"
log_event
fi
当我使用CLI工具时,我经常用到下面的片段来判断某个资源是否存在,但我并不关心输出结果。
if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
echo "none exist actually exist!"
fi
-e
属性后,如果执行失败的命令是紧接着while
或until
关键字的命令列表中的一部分、在if语句的测试条件中、在由&&
或||
连接的命令列表中(但不包括最后一个命令之后的命令)、在管道中但不是最后一条命令,或者如果通过使用!
将命令的返回状态进行反转,则shell不会退出。 - ruakh(ldd $2/bin/* || true) | grep "not found" | wc -l || true
- Igor Chubinset -o pipefail
的存在。当grep
找不到匹配项时,它会返回非零退出代码,这足以让shell认为整个管道命令的退出代码也是非零。 - Igor Chubin