我有一个相当复杂的一系列在bash是最终返回一个有意义的退出代码的命令。 各个地方在后面的脚本需要在命令集成功与否有条件分支。
目前我储存的退出代码和数值测试它,像这样:
long_running_command | grep -q trigger_word
status=$?
if [ $status -eq 0 ]; then
: stuff
else
: more code
if [ $status -eq 0 ]; then
: stuff
else
出于某种原因,感觉这应该是简单的。 我们有存储简单的退出代码,现在我们正在重复输入了数值实验操作在其上运行。 例如,我可以欺骗使用字符串输出,而不是返回代码,这是简单的测试:
status=$(long_running_command | grep trigger_word)
if [ $status ]; then
: stuff
else
: more code
if [ $status ]; then
: stuff
else
表面上这看起来更加直截了当,但我意识到这是肮脏的。
如果其他逻辑并非如此复杂,我只是跑这个曾经,我知道我可以代替测试操作的嵌入,但是当你需要重复使用在其他位置的结果,而无需重新运行 ,这是不理想测试 :
if long_running_command | grep -q trigger_word; then
: stuff
else
到目前为止,我发现的唯一的事情是命令替换的部分分配的代码:
status=$(long_running_command | grep -q trigger_word; echo $?)
if [ $status -eq 0 ]; then
: stuff
else
即使这在技术上不是一个拍摄任务(虽然有些人可能认为可读性更好),但必要的数值测试语法似乎仍然很麻烦给我。 也许我只是强迫症。
我缺少一个更优雅的方式来分配的退出代码给一个变量,然后在IT部门以后呢?
简单的解决方案:
output=$(complex_command)
status=$?
if (( status == 0 )); then
: stuff with "$output"
fi
: more code
if (( status == 0 )); then
: stuff with "$output"
fi
以上eleganter十岁上下
do_complex_command () {
# side effects: global variables
# store the output in $g_output and the status in $g_status
g_output=$(
command -args | commands | grep -q trigger_word
)
g_status=$?
}
complex_command_succeeded () {
test $g_status -eq 0
}
complex_command_output () {
echo "$g_output"
}
do_complex_command
if complex_command_succeeded; then
: stuff with "$(complex_command_output)"
fi
: more code
if complex_command_succeeded; then
: stuff with "$(complex_command_output)"
fi
要么
do_complex_command () {
# side effects: global variables
# store the output in $g_output and the status in $g_status
g_output=$(
command -args | commands
)
g_status=$?
}
complex_command_output () {
echo "$g_output"
}
complex_command_contains_keyword () {
complex_command_output | grep -q "$1"
}
if complex_command_contains_keyword "trigger_word"; then
: stuff with "$(complex_command_output)"
fi
你为什么不为需要以后发生的东西设置的标志?
cheeseballs=false
nachos=false
guppies=false
command
case $? in
42) cheeseballs=true ;;
17 | 31) cheeseballs=true; nachos=true; guppies=true;;
66) guppies=true; echo "Bingo!";;
esac
$cheeseballs && java -crash -burn
$nachos && python ./tex.py --mex
if $guppies; then
aquarium --light=blue --door=hidden --decor=squid
else
echo SRY
fi
正如在评论中指出通过@CharlesDuffy,在可变存储实际的命令是稍有可疑,和隐约触发击FAQ#50警告; 该代码读取(略&恕我直言)更自然地这样,但你必须要非常小心,你有过在任何时候变量的完全控制。 如果你有丝毫的怀疑,或许只是使用的字符串值和比较反对在每个路口的预期值。
[ "$cheeseballs" = "true" ] && java -crash -burn
等等等等; 或者你可以重构一些其他执行结构的布尔(选项的关联数组会是有意义的,但不能移植到POSIX sh
;一个PATH
般的字符串是灵活的,但也许是太非结构化)。
它的基础上,OP的澄清只有成功v故障(而不是具体的退出代码):
long_running_command | grep -q trigger_word || failed=1
if ((!failed)); then
: stuff
else
: more code
if ((!failed)); then
: stuff
else
- 设置仅在发生故障时成功指示符变量(经由
||
,即,如果返回一个非零退出代码)。 - 依赖于事实,没有定义的变量值为false算术条件
(( ... ))
- 必须注意的是,变量(
$failed
,在这个例子中)没有意外地在其他地方初始化。
(在一个侧面说明,作为@nos已经在评论已经提到的,你必须要小心,涉及管道命令;从man bash
(重点煤矿):
管道的返回状态是最后一个命令的退出状态 , 除非pipefail选项启用 。 如果pipefail启用,管道的返回状态是最后一个(最右边)的命令的退出值与非零状态,或零,如果全部顺利命令退出。
要设置pipefail
(这是默认关闭)时,使用set -o pipefail
; 打开它的电源,使用set +o pipefail
。)
如果你并不需要保存具体的退出状态,命令刚是成功还是失败(例如:是否grep
找到了比赛),我的使用假布尔变量存储结果:
if long_running_command | grep trigger_word; then
found_trigger=true
else
found_trigger=false
fi
# ...later...
if ! $found_trigger; then
# stuff to do if the trigger word WASN'T found
fi
#...
if $found_trigger; then
# stuff to do if the trigger WAS found
fi
笔记:
- 外壳并没有真正有布尔(真/假)的变量。 什么实际发生在这里是“真”和“假”被存储为found_trigger变量字符串; 当
if $found_trigger; then
if $found_trigger; then
执行,它运行的价值$found_trigger
为命令,它只是碰巧的是, true
命令总是成功和false
命令总是失败,从而导致“正确的事”的情况发生。 在if ! $found_trigger; then
if ! $found_trigger; then
if ! $found_trigger; then
,将“!” 切换成功/失败状态,有效地充当布尔“不”。 -
if long_running_command | grep trigger_word; then
if long_running_command | grep trigger_word; then
就相当于运行命令,然后使用if [ $? -ne 0 ]; then
if [ $? -ne 0 ]; then
if [ $? -ne 0 ]; then
检查其退出状态。 我觉得干净了一点,但你必须习惯的思维if
是检查命令的成功/失败,不只是测试布尔条件。 如果“主动” if
命令是不直观的给你,用一个单独的测试来代替。 正如查尔斯·达菲在评论中指出,这一招执行数据的命令,如果你没有对这些数据完全控制......你没有什么比你的脚本是要干什么控制。 所以永远不要设置一个假布尔变量来比固定字符串以外的任何“真”与“假”,并确保在使用前设置变量。 如果你必须在脚本中的任何平凡的执行流程,将所有假布尔变量理智的默认值(即“真”或“假”)的执行流程之前变得复杂。
不遵守这些规则可能会导致足够大,通过驱动一列货运火车的安全漏洞。
如果你不关心确切的错误代码,你可以这样做:
if long_running_command | grep -q trigger_word; then
success=1
: success
else
success=0
: failure
fi
if ((success)); then
: success
else
: failure
fi
使用0
为假, 1
为真在脚本中存储布尔我的首选方式。 if ((flag))
模拟物Ç很好。
如果你对退出代码护理,那么你可以这样做:
if long_running_command | grep -q trigger_word; then
status=0
: success
else
status=$?
: failure
fi
if ((status == 0)); then
: success
else
: failure
fi
我更反对0的明确的测试,而不是使用!
,不看错。
(是的, $?
确实在这里得到正确的值。)
嗯,这个问题有点模糊 - 如果可能的话,我建议考虑重构/简化,即
function check_your_codes {
# ... run all 'checks' and store the results in an array
}
###
function process_results {
# do your 'stuff' based on array values
}
###
create_My_array
check_your_codes
process_results
此外,除非你真的需要保存退出代码,那么就没有必要store_and_test -只是test_and_do,即使用的情况下,上述声明或类似的建议:
run_some_commands_and_return_EXIT_CODE_FROM_THE_LAST_ONE
if [[ $? -eq 0 ]] ; then do_stuff else do_other_stuff ; fi
:)
Dale
文章来源: Is there an elegant way to store and evaluate return values in bash scripts?