ChatGPT解决这个技术问题 Extra ChatGPT

Bash 忽略特定命令的错误

我正在使用以下选项

set -o pipefail
set -e

在 bash 脚本中停止执行错误。我有大约 100 行脚本正在执行,我不想检查脚本中每一行的返回码。

但是对于一个特定的命令,我想忽略该错误。我怎样才能做到这一点?


R
R. Oosterholt

解决方案:

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

+1。正如 Bash 参考手册 explains,“当设置 -e 属性时,shell 不会退出”“如果失败的命令是紧跟 whileuntil 关键字的命令列表的一部分,则if 语句中的测试,在 &&|| 列表中执行的任何命令的一部分,除了最后一个 &&|| 之后的命令,管道中除最后一个之外的任何命令,或者如果命令的返回状态正在与 ! 反转。"
@IgorChubin 我不知道为什么,但这不起作用 output=(ldd $2/bin/* || true) | grep "not found" | wc -l 脚本在 ldd 返回失败时在此行之后终止
(ldd $2/bin/* || true) | grep "not found" | wc -l || true
因为 set -o pipefail。当 grep 什么也没找到时,它返回非零退出代码,并且 shell 认为整个管道具有非零退出代码就足够了。
如果您想要保留返回值(不退出)的选项,请尝试 mycommand && true。这允许您在后续步骤中检查返回码并以编程方式处理它。
L
Lars Kotthoff

只需在要忽略错误的命令后添加 || true


我认为添加这一点很重要:此方法将允许响应代码和错误消息持续存在,而“!”下面概述的方法将更改响应代码,因此不会产生错误。这在使用 set -e 并尝试捕获错误消息时很重要:例如set -e; TEST=$(foo 2>&1 || true); echo $TEST
@Spanky我不太明白你的例子。您 set -e,将未找到的 bash 命令从 stderr 重定向到 $TEST。这如何保留响应代码?
@Spanky 您是否正在尝试做这样的事情set -e; TEST=$(foo 2>&1) || printf "ERROR $?: $TEST\n"
C
Ciro Santilli Путлер Капут 六四事

不要停止并保存退出状态

以防万一您希望脚本在特定命令失败时不停止,并且您还想保存失败命令的错误代码:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE

当命令返回 0 时,EXIT_CODE 未设置为零。但会捕获非零退出代码。知道为什么吗?
@Ankita13 因为如果第一个 command 为零,则需要运行 || 之后的内容。将其读作:如果 command 失败,则执行 EXIT_CODE=$?。您可能只需执行 command || echo "$?" 或使用“陷阱”进行更详细的调试。看到这个-> stackoverflow.com/a/6110446/10737630
我认为这可能是最好的答案。这就是我一直在寻找的东西。我不希望 shell 退出,但我确实想知道错误,所以我可以回应。多谢!
我已经使用这种技术手动强制停止 Gitlab CI 作业,因为即使退出代码为 1,我正在运行的命令似乎也会挂起,所以我最终自己退出了。
L
Lily Finley

更简洁:

! particular_script

从关于 set -ePOSIX specification(强调我的):

当此选项打开时,如果简单命令由于 Shell 错误的后果中列出的任何原因而失败或返回退出状态值 >0,并且在一段时间、直到或 if 关键字之后不属于复合列表的一部分,并且不是 AND 或 OR 列表的一部分,也不是前面有 ! 的管道保留字,则shell应立即退出。


这只是反转命令的退出代码,因此成功完成的命令将返回 1 而不是 0,并使用 -e 使脚本失败。
我的理解是 ! 无论如何都会阻止 shell 退出。 This script 在我运行时显示消息 Still alive!,表示脚本运行完成。你看到不同的行为吗?
你是对的,它会反转退出状态,但是当命令以 0 或 1 结尾时不会使脚本崩溃。我不专心。无论如何,感谢您引用文档,我将表达式放在 if 子句中并解决了问题。
这是 IMO 的最佳解决方案,因为在许多情况下,我想忽略 particular_script 的返回值,但如果 particular script 是一个函数,我确实想忽略语句的返回值函数里面。 || 解决方案将忽略 particular_script 函数体内的所有返回码,这通常不是您想要的 (stackoverflow.com/a/37191242/985292)。
虽然 || 在破折号中不起作用,但确实如此。谢谢!
T
Timo

除了“返回 true”,您还可以使用“noop”或 null 实用程序(如 POSIX specs 中所述): 并且只是“什么都不做”。你会省下几封信。 :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."

虽然 ||: 不像 || 那样清晰真的(这可能会使非专家用户感到困惑),我喜欢简洁
此变体不返回任何在 CI 中可能很重要的文本。
很好,但是还有其他方法可以更清楚地返回 null 吗?
@august0490 alias null=:,如果您觉得更清楚,可以使用 null 代替 :
v
volingas

如果您想防止脚本失败并收集返回码:

command () {
    return 1  # or 0 for success
}

set -e

command && returncode=$? || returncode=$?
echo $returncode

无论命令成功还是失败,都会收集 returncode


你怎么做这个内联?
A
Almaz Gareev

感谢上面的简单解决方案:

<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


K
Konard

从这里没有解决方案对我有用,所以我找到了另一个解决方案:

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 操作中对我有用的方法
R
Robert.C
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

P
Payman

在使用 CLI 工具时,我一直在使用下面的代码片段,我想知道是否存在某些资源,但我不关心输出。

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi

这似乎是一种非常迂回且价格适中的说法if [ -r not_exist ]
Q
Q-life

我有点喜欢这个解决方案:

: `particular_script`

执行反引号之间的命令/脚本,并将其输出馈送到命令“:”(相当于“真”)

$ false
$ echo $?
1
$ : `false`
$ echo $?
0

编辑:修正了丑陋的错字


F
Foto Blysk

虽然 || true 是首选,但您也可以这样做

var=$(echo $(exit 1)) # it shouldn't fail