在一个nodejs项目中,我有一个快捷方式
yarn lint
,它以这种方式运行几个linter:
lint_1 && lint_2 && lint_3
如果其中任何一个发现错误,它会返回错误代码,因此
yarn lint
本身会返回错误代码,结果 - 构建失败。
它工作得很好,捕获了所有错误,尽管有一个小问题:如果 linter 因错误代码而失败 - 其余的 linter 将不会被执行。
我想要的 - 执行所有这些(这样它们都会打印所有错误),然后才会失败。
我知道我可以创建一个 bash 脚本(我将在
yarn lint
中运行),逐个运行每个 linter 收集返回代码,然后检查是否有任何代码非零 - exit 1
并且它将失败yarn lint
。但我想知道是否有更优雅的方法来做到这一点?
您可以捕获 ERR 并设置一个标志。这将运行每个 linter,如果其中任何一个失败,就会失败退出:
#!/bin/bash
result=0
trap 'result=1' ERR
lint_1
lint_2
lint_3
exit "$result"
我想要的 - 执行所有这些(这样它们都会打印所有错误)然后失败
基本上我们有一个要捕获的退出代码列表。如果其中任何一个非零,我们需要将变量设置为非零值。将其扩展为列表,如下所示:
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 第二个片段剪掉。
我认为这干净、清晰、简洁:
declare -i result=0 # declare $result is an integer
lint_1; result+=$?
lint_2; result+=$?
exit "$result"