我试图在一个循环中调用一个函数,然后优雅地处理并在它抛出时继续。
如果我省略|| handle_error
,它就会像预期的那样停止整个脚本。
如果我离开foo is fine
,则会在错误后打印handle_error
,并且根本不会执行#!/bin/bash
set -e
things=(foo bar)
function do_something {
echo "param: $1"
# just throw on first loop run
# this statement is just a way to selectively throw
# not part of a real use case scenario where the command(s)
# may or may not throw
if [[ $1 == "foo" ]]; then
throw_error
fi
# this line should not be executed when $1 is "foo"
echo "$1 is fine."
}
function handle_error {
echo "$1 failed."
}
for thing in ${things[@]}; do
do_something $thing || handle_error $thing
done
echo "done"
。这也是一种预期的行为,它只是它的运作方式。
param: foo
./test.sh: line 12: throw_error: command not found
foo is fine.
param: bar
bar is fine.
done
产量
param: foo
./test.sh: line 12: throw_error: command not found
foo failed.
param: bar
bar is fine.
done
我想拥有的是
do_something
修改
do_something
并不需要返回任何内容。它只是抛出一个函数的一个例子,我可能会从示例源代码中删除它,因为我无法控制其内容,也不想对其进行测试,并且测试其中的每个命令是不可行的。
修改
您无法触及make
逻辑。我之前说过,它只是一个包含一组可能引发错误的指令的函数。它可能是一个错字,它可能在CI环境中host
失败,可能是网络错误。
答案 0 :(得分:0)
#!/bin/bash
set -e
things=(foo bar)
function do_something() {
echo "param: $1"
ret_value=0
if [[ $1 == "foo" ]]; then
ret_value=1
elif [[ $1 == "fred" ]]; then
ret_value=2
fi
echo "$1 is fine."
return $ret_value
}
function handle_error() {
echo "$1 failed."
}
for thing in ${things[@]}; do
do_something $thing || handle_error $thing
done
echo "done"
请参阅上面的评论以获得解释。您无法在不创建返回值的情况下测试返回值,这应该是显而易见的。并且||测试返回值,基本上是一个大于0的值。像&&测试为0.我认为这或多或少是正确的。我相信bash返回值限制是254?我想说。必须是0到254之间的整数。不能是字符串,浮点数等
http://tldp.org/LDP/abs/html/complexfunct.html
函数返回一个值,称为退出状态。这类似于 命令返回的退出状态。退出状态可能是 由return语句显式指定,否则它是退出 函数中最后一个命令的状态(如果成功,则为0,以及a 如果不是非零错误代码)。此退出状态可用于 脚本通过引用它作为$?。这种机制有效地允许 脚本函数具有"返回值"类似于C函数。
实际上,foo会返回127命令未找到错误。我认为。我必须进行测试才能确定。
[更新} 不,echo是最后一个命令,正如您从输出中看到的那样。并且最后一个回声的结果是0,所以函数返回0.所以你想要抛弃这个概念并转到像陷阱这样的东西,假设你不能触及函数的内部,很奇怪。
echo fred; echo reval: $?
fred
reval: 0
What does set -e mean in a bash script?
-e Exit immediately if a command exits with a non-zero status.
但它不是很可靠,被认为是一种不好的做法,更好地使用:
trap 'do_something' ERR
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html看到陷阱,这可能会做你想要的。但不是||,除非你添加回报。
答案 1 :(得分:0)
我找到的解决方案是将函数保存在单独的文件中并在子shell中执行。缺点是我们失去了所有当地人。
<强> do-something.sh 强>
2015-11-14T02:42:05.497208+00:00 heroku[api]: Deploy 63ae6bd by email@gmail.com
2015-11-14T02:42:05.497305+00:00 heroku[api]: Release v4 created by email@gmail.com
2015-11-14T02:42:05.651545+00:00 heroku[slug-compiler]: Slug compilation started
2015-11-14T02:42:05.651555+00:00 heroku[slug-compiler]: Slug compilation finished
2015-11-14T02:42:05.820048+00:00 heroku[web.1]: State changed from up to starting
2015-11-14T02:42:08.998026+00:00 heroku[web.1]: Stopping all processes with SIGTERM
2015-11-14T02:42:09.746422+00:00 heroku[web.1]: Starting process with command `vendor/bin/heroku-php-apache2`
2015-11-14T02:42:09.909064+00:00 app[web.1]: Going down, terminating child processes...
2015-11-14T02:42:10.844965+00:00 heroku[web.1]: Process exited with status 0
2015-11-14T02:42:12.439647+00:00 app[web.1]: Starting php-fpm...
2015-11-14T02:42:12.243079+00:00 app[web.1]: Optimizing defaults for 1X dyno...
2015-11-14T02:42:12.435588+00:00 app[web.1]: 4 processes at 128MB memory limit.
2015-11-14T02:42:14.442033+00:00 app[web.1]: Starting httpd...
2015-11-14T02:42:14.672772+00:00 heroku[web.1]: State changed from starting to up
2015-11-14T02:44:38.663711+00:00 heroku[router]: at=info method=GET path="/" host=mywebsite.herokuapp.com request_id=45aae2bd-a6f8-4023-86cf-6aedd5d23882 fwd="138.110.234.184" dyno=web.1 connect=12ms service=2ms status=500 bytes=224
2015-11-14T02:44:38.663113+00:00 app[web.1]: [14-Nov-2015 02:44:38 UTC] PHP Parse error: syntax error, unexpected '?' in /app/index.php on line 1
2015-11-14T02:44:38.663580+00:00 app[web.1]: 10.146.233.83 - - [14/Nov/2015:02:44:38 +0000] "GET / HTTP/1.1" 500 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36
<强> my-script.sh 强>
#!/bin/bash
set -e
echo "param: $1"
if [[ $1 == "foo" ]]; then
throw_error
fi
echo "$1 is fine."
产量
#!/bin/bash
set -e
things=(foo bar)
function handle_error {
echo "$1 failed."
}
for thing in "${things[@]}"; do
./do-something.sh "$thing" || handle_error "$thing"
done
echo "done"
如果有更优雅的方式,我会将其标记为正确答案。将在48小时内再次检查。
修改强>
感谢@PeterCordes评论和this other answer我找到了另一个不需要单独文件的解决方案。
param: foo
./do-something.sh: line 8: throw_error: command not found
foo failed.
param: bar
bar is fine.
done
正确产生
#!/bin/bash
set -e
things=(foo bar)
function do_something {
echo "param: $1"
if [[ $1 == "foo" ]]; then
throw_error
fi
echo "$1 is fine."
}
function handle_error {
echo "$1 failed with code: $2"
}
for thing in "${things[@]}"; do
set +e; (set -e; do_something "$thing"); error=$?; set -e
((error)) && handle_error "$thing" $error
done
echo "done"
答案 2 :(得分:-1)
尝试
if [[ "$1" == "foo" ]]; then
foo
fi
我想知道它是否试图在条件测试中执行命令foo
?
来自bash参考:
-e 如果管道(参见管道)可能包含一个简单命令(参见简单命令),列表(参见列表),则立即退出 或复合命令(请参阅复合命令)返回非零值 状态。如果失败的命令是shell的一部分,则shell不会退出 紧跟一段时间或直到关键字的命令列表,部分 if语句中的测试,是&amp;&amp ;;中执行的任何命令的一部分。 或||列表除了最后一个&amp;&amp;之后的命令或者||,任何 管道中的命令但是最后一个,或者命令的返回状态 正在被倒置!
如您所见,如果在测试条件中发生错误,则脚本将继续无视并返回0.
-
所以作为回应,我注意到文档继续:
如果子shell以外的复合命令返回非零状态 因为命令失败而-e被忽略,所以shell会这样做 不退出。
好吧,因为你的for
由echo
继承,所以没有理由抛出错误!