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

时间:2019-01-18 03:43:52

标签: bash shell scripting automation continuous-integration

在一个nodejs项目中,我有一个快捷方式yarn lint,该快捷方式以这种方式运行了两个linter:

lint_1 && lint_2 && lint_3

如果其中任何一个发现错误,它将返回错误代码,结果yarn lint本身将返回错误代码,结果是-构建失败。

它工作得很好,尽管有一个小问题,但可以捕获所有错误:如果短绒棉失败并显示错误代码-其余的短绒棉将不会执行。

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

我知道我可以创建一个bash脚本(将在yarn lint中运行),逐一收集返回代码,然后运行每个linter,然后检查代码是否为非零-{{ 1}},它将失败exit 1。但是我想知道是否还有更优雅的方法?

2 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:2)

  

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

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

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没有2d数组。使用eval可以解决引用的参数。这是可行的。您必须使用eval来双重清空数组“指针” /名称,但是可以。请注意,evalevil

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 STATUS123 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。