我正在用Bash编写一个脚本来测试一些代码。但是,如果首先编译代码失败,运行测试似乎很愚蠢,在这种情况下,我只是中止测试。
有没有办法可以在没有将整个脚本包含在while循环中并使用中断的情况下执行此操作?有点像dun dun dun goto?
使用set -e
#!/bin/bash
set -e
/bin/command-that-fails
/bin/command-that-fails2
脚本将在第一行失败后终止(返回非零退出代码)。在这种情况下,command-that-failed2将不会运行。
如果要检查每个命令的返回状态,则脚本将如下所示:
#!/bin/bash
# I'm assuming you're using make
cd /project-dir
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
使用set -e,它看起来像:
#!/bin/bash
set -e
cd /project-dir
make
cd /project-dir2
make
任何失败的命令都会导致整个脚本失败并返回退出状态,您可以使用$?进行检查。如果您的脚本很长或者您正在构建很多东西,那么如果您在任何地方添加返回状态检查,那将会非常难看。
一个坏屁股的SysOps家伙曾经教过我三指爪技术:
yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
这些功能是* NIX OS和shell风格强大。将它们放在脚本的开头(bash或其他),try()
你的声明和代码。
(根据flying sheep评论)。
yell
:打印脚本名称和stderr
的所有参数:
$0
是剧本的路径;
$*
都是争论。
>&2
意味着>
将stdout重定向到&pipe 2
。管道1
将是stdout
本身。die
和yell
一样,但以非0退出状态退出,这意味着“失败”。try
使用||
(boolean OR
),如果左侧失败,则仅评估右侧。
$@
是所有的争论,但different。如果您将使用source
调用脚本,则可以使用return <x>
,其中<x>
将是脚本退出状态(使用非零值表示错误或false)。但是如果你调用一个可执行脚本(即,直接用它的文件名),return语句将导致一个抱怨(错误消息“返回:只能从函数或源脚本'返回'”)。
如果使用exit <x>
,当使用source
调用脚本时,将导致退出启动脚本的shell,但是可执行脚本将按预期终止。
要在同一脚本中处理任何一种情况,您都可以使用
return <x> 2> /dev/null || exit <x>
这将处理适合的调用。假设您将在脚本的顶层使用此语句。我建议不要直接从函数中退出脚本。
注意:<x>
应该只是一个数字。
我经常包含一个名为run()的函数来处理错误。我想要进行的每个调用都会传递给此函数,以便在发生故障时退出整个脚本。这比set -e解决方案的优势在于,当一行失败时,脚本不会以静默方式退出,并且可以告诉您问题所在。在以下示例中,未执行第3行,因为脚本在调用false时退出。
function run() {
cmd_output=$(eval $1)
return_value=$?
if [ $return_value != 0 ]; then
echo "Command $1 failed"
exit -1
else
echo "output: $cmd_output"
echo "Command succeeded."
fi
return $return_value
}
run "date"
run "false"
run "date"
而不是if
构造,你可以利用short-circuit evaluation:
#!/usr/bin/env bash
echo $[1+1]
echo $[2/0] # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]
注意由于交替运算符的优先级而必需的括号对。 $?
是一个特殊的变量,用于退出最近调用的命令的代码。
我有同样的问题,但不能问它,因为它会是重复的。
使用exit时接受的答案在脚本稍微复杂时不起作用。如果使用后台进程检查条件,则退出仅退出该进程,因为它在子shell中运行。要杀死脚本,你必须明确地杀死它(至少这是我所知道的唯一方法)。
这是一个关于如何做的小脚本:
#!/bin/bash
boom() {
while true; do sleep 1.2; echo boom; done
}
f() {
echo Hello
N=0
while
((N++ <10))
do
sleep 1
echo $N
# ((N > 5)) && exit 4 # does not work
((N > 5)) && { kill -9 $$; exit 5; } # works
done
}
boom &
f &
while true; do sleep 0.5; echo beep; done
这是一个更好的答案,但仍然不完整,我真的不知道如何摆脱繁荣部分。