我有一个bash脚本,对我的源代码运行三次检查,然后exit 0
如果所有命令都成功,或exit 1
如果其中任何一个失败:
#!/bin/bash
test1 ./src/ --test-1=option
exit_1=$?
test2 ./src/ test-2-options
exit_2=$?
test3 ./src/ -t 3 -o options
exit_3=$?
# Exit with error if any of the above failed
[[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]]
exit $?
此代码有效,但感觉过长且冗长。有什么方法可以做得更好吗?具体来说,我不满意:
[[ ... ]]
,然后在下一行收集退出代码以退出[[ $var -eq 0 ]]
,而不是将它们视为布尔值理想情况下,最终结果会更具可读性:
exit_1=( test1 ./src/ --test-1=option )
exit_2=( test2 ./src/ test-2-options )
exit_3=( test3 ./src/ -t 3 -o options )
# Exit with error if any of the above failed
exit ( $exit_1 && $exit_2 && $exit_3 )
我考虑过的一些事情:
将错误代码放入一行变量中
exit_1=$( test1 ./src/ --test-1=option )$?
exit_2=$( test2 ./src/ test-2-options )$?
exit_3=$( test3 ./src/ -t 3 -o options )$?
这样可以使这一点变得更短,但我以前从未见过其他人使用它。这是明智/理智的事吗?这有什么问题吗?
只是运行测试,&&他们在一起:
test1 ./src/ --test-1=option && \
test2 ./src/ test-2-options && \
test3 ./src/ -t 3 -o options
status=$?
不工作,因为bash短路。如果test1
失败,则test2和test3不会运行,我希望它们全部运行。
使用|| exit
[[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]] || exit 1
这节省了一行尴尬的退出代码和变量,但exit 1
的重要位现在正好在你可以错过它的行的末尾。理想情况下,这样的事情会起作用:
exit [[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]]
当然,这不工作,因为[[
返回其输出而不是回显它。
exit $( [[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]] ; echo $? )
工作,但仍然看起来像一个可怕的污泥
未明确处理exit-codes-as-boolean
[[ $exit_1 && $exit_2 && $exit_3 ]]
这不符合您的希望。最简单的&& amp;存储在变量中的三个返回码与完整$var -eq 0 && ...
一起使用。当然有一个更好的方式?
我知道bash不是一个很好的编程语言 - 如果你甚至可以称之为 - 但是有什么方法可以让它变得不那么尴尬吗?
答案 0 :(得分:8)
您可以将bash
的算术命令一起用于OR
退出代码,并取消结果,如果任何代码非零,则退出代码为1。首先,一个例子:
$ ! (( 0 | 0 | 0 )); echo $?
0
$ ! (( 1 | 0 | 0 )); echo $?
1
现在,您的脚本:
#!/bin/bash
test1 ./src/ --test-1=option; exit_1=$?
test2 ./src/ test-2-options; exit_2=$?
test3 ./src/ -t 3 -o options; exit_3=$?
# Exit with error if any of the above failed. No need for a final
# call to exit, if this is the last command in the script
! (( $exit_1 || $exit_2 || $exit_3 ))
或者通常,您可以在运行任意数量的测试时累积退出代码:
#!/bin/bash
# Unfortunately, ||= is not an assignment operator in bash.
# You could use |=, I suppose; you may not be able to assign
# any meaning to any particular non-zero value, though.
test1 ./src/ --test-1=option; (( exit_status = exit_status || $? ))
test2 ./src/ test-2-options; (( exit_status = exit_status || $? ))
test3 ./src/ -t 3 -o options; (( exit_status = exit_status || $? ))
# ...
testn ./src "${final_option_list[@]}"; (( exit_status = exit_status || $? ))
exit $exit_status # 0 if they all succeeded, 1 if any failed
答案 1 :(得分:3)
一些改进
[ $exit_1$exit_2$exit3 = 000 ]
# no exit needed here, script exits with code from last command
答案 2 :(得分:3)
我一直在寻找这个问题的答案,并决定采用与@ chepner类似的方式但不使用bash的算术表达式:
#!/bin/bash
failed=0
test1 ./src/ --test-1=option || failed=1
test2 ./src/ test-2-options || failed=1
test3 ./src/ -t 3 -o options || failed=1
# Exit with error if any of the above failed
if [ "$failed" -ne 0 ] ; then
exit
fi
您只需在开头设置一个标志,如果任何语句失败,则将标志设置为1。 ||
是关键所在。
答案 3 :(得分:0)
您可以使用以下行分配命令的退出代码:
RES1=$(CMD > /dev/null)$?
示例:
RES1=$(test1 ./src/ --test-1=option > /dev/null )$?
所以你的代码将是:
exit_1=$( test1 ./src/ --test-1=option > /dev/null )$?
exit_2=$( test2 ./src/ test-2-options > /dev/null )$?
exit_3=$( test3 ./src/ -t 3 -o options > /dev/null )$?
# Exit with error if any of the above failed
exit ( $exit_1 && $exit_2 && $exit_3 )
答案 4 :(得分:0)
为什么需要三个不同的变量?
fn() {
local -i st
test1 ./src/ --test-1=option
st=$?
test2 ./src/ test-2-options
(( st = ($? || st) )) # Use arithmetic expression to or the values at each step
test3 ./src/ -t 3 -o options
(( 0 == ($? || st) ))
}