运行一组命令,如果失败则返回错误代码

问题描述 投票:0回答:3

在一个nodejs项目中,我有一个快捷方式

yarn lint
,它以这种方式运行几个linter:

lint_1 && lint_2 && lint_3

如果其中任何一个发现错误,它会返回错误代码,因此

yarn lint
本身会返回错误代码,结果 - 构建失败。

它工作得很好,捕获了所有错误,尽管有一个小问题:如果 linter 因错误代码而失败 - 其余的 linter 将不会被执行。

我想要的 - 执行所有这些(这样它们都会打印所有错误),然后才会失败。

我知道我可以创建一个 bash 脚本(我将在

yarn lint
中运行),逐个运行每个 linter 收集返回代码,然后检查是否有任何代码非零 -
exit 1
并且它将失败
yarn lint
。但我想知道是否有更优雅的方法来做到这一点?

bash shell scripting automation continuous-integration
3个回答
7
投票

您可以捕获 ERR 并设置一个标志。这将运行每个 linter,如果其中任何一个失败,就会失败退出:

#!/bin/bash
result=0
trap 'result=1' ERR
lint_1
lint_2
lint_3
exit "$result"         

3
投票

我想要的 - 执行所有这些(这样它们都会打印所有错误)然后失败

基本上我们有一个要捕获的退出代码列表。如果其中任何一个非零,我们需要将变量设置为非零值。将其扩展为列表,如下所示:

result=0
if ! lint_1; then result=1; fi
if ! lint_2; then result=1; fi
if ! lint_3; then result=1; fi
exit "$result"

作为一名程序员,我发现我们这里有一个模式。所以我们可以使用数组,但 bash 没有二维数组。这将是一个使用

eval
来绕过引用参数的解决方法。这是可行的。您必须使用
eval
来双重评估数组“指针”/名称,但可以工作。请注意,
eval
evil

cmds_1=(lint_1 "arg with spaces you pass to lint_1")
cmds_2=(lint_2)
cmds_3=(lint_3)

result=0
# compgen results list of variables starting with `cmds_`
# so naming is important
for i in $(compgen -v cmds_); do
    # at first, `$i` is only expanded
    # then the array is expanded `"${cmds_?[@]}"`
    if ! eval "\"\${$i[@]}\""; then
        result=1
    fi
done
exit "$result"

我们也可以使用 xargs。从手册中

EXIT STATUS
变为
123 if __any__ invocation of the command exited with status 1-125
。如果您知道您的程序将在 1-125 退出状态之间退出,您可以(通常 xargs 无论如何都能正确处理不同的退出状态(返回 123),但让我们保持一致):

xargs -l1 -- bash -c '"$@"' -- <<EOF
lint_1 "arg with spaces you pass to lint_1"
lint_2
lint_3
EOF
result=$?          # or just exit "$?"
exit "$result"

看起来异常干净。附带说明一下,只需将

-P <number of jobs>
传递给
xargs
,您就可以并行执行所有命令。您可以通过处理 bash 脚本内的错误来适应 1-125 的错误范围,即。

xargs -l1 -- bash -c '"$@" || exit 1' -- <<EOF
lint_1 "arg with spaces you pass to lint_1"
lint_2
lint_3
EOF
result=$?
exit "$result"

我还有另一个想法。在每个命令之后,我们可以在专用文件描述符上输出返回状态。然后从所有返回状态中过滤零并检查流上是否有任何其他状态。如果是,我们应该以非零状态退出。这感觉像是一个工作完成的过程,基本上与第一个代码片段相同,但

if ! ....; then result=1; fi
被简化为
; echo $? >&10

tmp=$(mktemp)
(
    lint_1 "arg with spaces you pass to lint_1"; echo $? >&10
    lint_2; echo $? >&10
    lint_3; echo $? >&10
) 10> >(
    [ -z "$(grep -v 0)" ]
    echo $? > "$tmp"
)
result="$(cat "$tmp"; rm "$tmp")"
exit "$result"

从提供的选项来看,我会选择其他答案;)或将 xargs 第二个片段剪掉。


0
投票

我认为这干净、清晰、简洁:

declare -i result=0  # declare $result is an integer
lint_1; result+=$?
lint_2; result+=$?
exit "$result"
© www.soinside.com 2019 - 2024. All rights reserved.