Bash 忽略特定命令的错误
- 2024-10-09 09:10:00
- admin 原创
- 217
问题描述:
我正在使用以下选项
set -o pipefail
set -e
在 bash 脚本中,发生错误时停止执行。我有大约 100 行脚本正在执行,但我不想检查脚本中每一行的返回代码。
但对于某个特定命令,我想忽略错误。我该怎么做?
解决方案 1:
解决方案:
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
解决方案 2:
|| true
只需在您想要忽略错误的命令后添加即可。
解决方案 3:
不要停止并保存退出状态
如果您希望脚本在某个命令失败时不停止,并且还想保存失败命令的错误代码:
set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE
解决方案 4:
更简洁地说:
! particular_script
从POSIX 规范中可以看出set -e
(重点是我的):
当此选项处于打开状态时,如果简单命令由于 Shell 错误的后果中列出的任何原因而失败或返回退出状态值 >0,并且不是 while、until 或 if 关键字之后的复合列表的一部分,也不是 AND 或 OR 列表的一部分,也不是以! 保留字开头的管道,则 shell 应立即退出。
解决方案 5:
除了“返回 true”之外,您还可以使用“noop”或 null 实用程序(如POSIX 规范中所述):
并“不执行任何操作”。这样可以节省一些字母。:)
#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."
解决方案 6:
我找到了另一种方法来解决这个问题:
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 中)。
解决方案 7:
感谢上面提供的简单解决方案:
<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
如果需要的话,我们可以阻止进一步的行动。
解决方案 8:
如果您想防止脚本失败并收集返回代码:
command () {
return 1 # or 0 for success
}
set -e
command && returncode=$? || returncode=$?
echo $returncode
returncode
无论命令成功还是失败都会被收集。
解决方案 9:
output=$(*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
解决方案 10:
在使用 CLI 工具时我一直在使用下面的代码片段,我想知道某些资源是否存在,但我不关心输出。
if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
echo "none exist actually exist!"
fi
解决方案 11:
while|| true
是首选,但你也可以这样做
var=$(echo $(exit 1)) # it shouldn't fail
解决方案 12:
我有一个类似但不相同的情况:
#!/bin/bash
CHECK=$(unbound-checkconf 2>&1)
if [[ $CHECK == *"no errors"* ]]; then
echo $CHECK
else
echo "Failed!"
fi
仅添加:2>&1
前:
[root@dns-recursive ~]# ./unbound.sh
/etc/unbound/unbound.conf:16: error: unknown keyword 'erver'
/etc/unbound/unbound.conf:16: error: stray ':'
/etc/unbound/unbound.conf:20: error: syntax error
read /etc/unbound/unbound.conf failed: 3 errors in configuration file
Failed!
后:
[root@dns-recursive ~]# ./unbound.sh
Failed!
解决方案 13:
我有点喜欢这个解决方案:
: `particular_script`
执行反引号之间的命令/脚本,并将其输出提供给命令“:”(相当于“true”)
$ false
$ echo $?
1
$ : `false`
$ echo $?
0
编辑:修正了难看的打字错误