bash 如何在bash中循环退出状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14059342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get the exit status a loop in bash
提问by Sriharsha Kalluru
I know how to check the status of the previously executed command using $?, and we can make that status using exit command. But for the loops in bash are always returning a status 0 and is there any way I can break the loop with some status.
我知道如何使用 $? 检查先前执行的命令的状态,我们可以使用 exit 命令来设置该状态。但是对于 bash 中的循环总是返回状态 0,有什么办法可以用某种状态打破循环。
#!/bin/bash
while true
do
if [ -f "/test" ] ; then
break ### Here I would like to exit with some status
fi
done
echo $? ## Here I want to check the status.
回答by William Pursell
The status of the loop is the status of the last command that executes. You can use break to break out of the loop, but if the break is successful, then the status of the loop will be 0. However, you can use a subshell and exit instead of breaking. In other words:
循环的状态是执行的最后一个命令的状态。可以使用 break 来跳出循环,但是如果 break 成功,则循环的状态将为0。但是,您可以使用子shell 并退出而不是中断。换句话说:
for i in foo bar; do echo $i; false; break; done; echo $? # The loop succeeds
( for i in foo bar; do echo $i; false; exit; done ); echo $? # The loop fails
You could also put the loop in a function and return a value from it.
您也可以将循环放入一个函数中并从中返回一个值。
回答by tripleee
Something like this?
像这样的东西?
while true; do
case $RANDOM in *0) exit 27 ;; esac
done
Or like this?
或者像这样?
rc=0
for file in *; do
grep fnord "$file" || rc=$?
done
exit $rc
The real question is to decide whether the exit code of the loop should be success or failure if one iteration fails. There are scenarios where one make more sense than the other, and other where it's not at all clear cut.
真正的问题是如果一次迭代失败,决定循环的退出代码是成功还是失败。在某些情况下,一种比另一种更有意义,而另一些则完全不明确。
回答by hagello
The bash manual says:
bash 手册说:
while list-1; do list-2; done
until list-1; do list-2; done
[..]The exit status of the while and until commands is the exit status
of the last command executed in list-2, or zero if none was executed.[..]
The last command that is executed insidethe loop is break. And the exit value of breakis 0 (see: help break).
在循环内执行的最后一个命令是break. 的退出值为break0(参见:)help break。
This is why your program keeps exiting with 0.
这就是为什么您的程序一直以 0 退出的原因。
回答by hagello
I think what you should be asking is: How can I wait until a file or a directory (/test) gets created by another process?
我想你应该问的是:我怎么能等到/test另一个进程创建了一个文件或目录()?
What you are doing up to now is polling with full power. Your loop will allocate up to 100% of the processing power of one core. The keyword is "polling", which is ethically wrongby the standards of computer scientists.
到目前为止,您正在做的是全权轮询。您的循环将分配最多 100% 的一个内核的处理能力。关键字是“轮询”,按照计算机科学家的标准,这在道德上是错误的。
There are two remedies:
有两种补救措施:
- insert a sleep statement in your loop; advantage: very simple; disadvantage: the delay will be an arbitrary trade-off between CPU load and responsiveness. ("Arbitrary" is ethically wrong, too).
- use a notification mechanism like
inotify(see:man inotify); advantage: no CPU load, great responsiveness, no delays, no arbitrary constants in your code; disadvantage:inotifyis a kernel API – you need some code to access it:inotify-toolsor some C/Perl/Python code. Have a look at inotify and bash!
- 在循环中插入睡眠语句;优点:非常简单;缺点:延迟将是 CPU 负载和响应能力之间的任意权衡。(“任意”在道德上也是错误的)。
- 使用通知机制
inotify(见:)man inotify;优点:没有 CPU 负载,响应速度快,没有延迟,代码中没有任意常量;缺点:inotify是一个内核 API——你需要一些代码来访问它:inotify-tools或者一些 C/Perl/Python 代码。看看inotify 和 bash!
回答by code4cause
The break builtin for bash does allow you to accomplish what you are doing, just break with a negative value and the status returned by $? will be 1:
bash 内置的 break 确实允许你完成你正在做的事情,只是用一个负值和 $? 将是 1:
while true
do
if [ -f "./test" ] ; then
break -1
fi
done
echo $? ## You'll get 1 here..
Note, this is documented in the help for the break builtin:
请注意,这在 break 内置的帮助中有记录:
help break
break: break [n] Exit for, while, or until loops.
Exit a FOR, WHILE or UNTIL loop. If N is specified, break N enclosing loops.
Exit Status: The exit status is 0 unless N is not greater than or equal to 1.
break: break [n] 退出 for、while 或 until 循环。
退出 FOR、WHILE 或 UNTIL 循环。如果指定了 N,则中断 N 个封闭循环。
退出状态:退出状态为 0,除非 N 不大于或等于 1。
You can break out of n number of loops or send a negative value for breaking with a non zero return, ie, 1
您可以中断 n 次循环或发送负值以使用非零返回进行中断,即 1
I agree with @hagello as one option doing a sleep and changing the loop:
我同意@hagello 作为一种选择来做睡眠和改变循环:
#!/bin/bash
timeout=120
waittime=0
sleepinterval=3
until [[ -f "./test" || ($waittime -eq $timeout) ]]
do
$(sleep $sleepinterval)
waittime=$((waittime + sleepinterval))
echo "waittime is $waittime"
done
if [ $waittime -lt $sleepinterval ]; then
echo "file already exists"
elif [ $waittime -lt $timeout ]; then
echo "waited between $((waittime-3)) and $waittime seconds for this to finish..."
else
echo "operation timed out..."
fi
回答by Kenneth Karlsson
I would like to submit an alternative solution which is simpler and I think more elegant:
我想提交一个更简单且我认为更优雅的替代解决方案:
(while true
do
if [ -f "test" ] ; then
break
fi
done
Of course of this is part of a script then you could user return 1 instead of exit 1
exit 1
)
echo "Exit status is: $?"
回答by VonC
Git 2.27 (Q2 2020), offers a good illustration of the exit status in a loop, here within the context of aborting a failing test early (e.g. by exiting a loop), which is to say "return 1".
Git 2.27(2020 年第二季度)很好地说明了循环中的退出状态,这里是在提前中止失败测试(例如通过退出循环)的上下文中,即“返回 1”。
See commit 7cc112d(27 Mar 2020) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster--in commit b07c721, 28 Apr 2020)
请参阅Junio C Hamano() 的commit 7cc112d(2020 年 3 月 27 日)。(由Junio C Hamano合并-- --在提交 b07c721 中,2020 年 4 月 28 日)gitstergitster
t/README: suggest how to leave test early with failureHelped-by: Jeff King
Over time, we added the support to our test framework to make it easy to leave a test early with failure, but it was not clearly documented in
t/READMEto help developers writing new tests.
t/README: 建议如何在失败时尽早离开测试帮助者:杰夫·金
随着时间的推移,我们为我们的测试框架添加了支持,以便在失败的情况下尽早离开测试,但它没有明确记录在
t/README帮助开发人员编写新测试的过程中。
The documentation now includes:
该文档现在包括:
Be careful when you loop
You may need to verify multiple things in a loop, but the following does not work correctly:
test_expect_success 'test three things' ' for i in one two three do test_something "$i" done && test_something_else 'Because the status of the loop itself is the exit status of the
test_somethingin the last round, the loop does not fail when "test_something" for "one" or "two" fails.
This is not what you want.Instead, you can break out of the loop immediately when you see a failure.
Because alltest_expect_*snippets are executed inside a function, "return 1" can be used to fail the test immediately upon a failure:test_expect_success 'test three things' ' for i in one two three do test_something "$i" || return 1 done && test_something_else 'Note that we still
&&-chain the loop to propagate failures from earlier commands.
循环时要小心
您可能需要在循环中验证多项内容,但以下内容无法正常工作:
test_expect_success 'test three things' ' for i in one two three do test_something "$i" done && test_something_else '因为循环本身的状态是
test_something上一轮的退出状态,所以当“test_something” for “one”或“two”失败时循环不会失败。
这不是你想要的。相反,您可以在看到失败时立即跳出循环。
因为所有代码test_expect_*片段都在一个函数内执行,"return 1" 可用于在失败时立即使测试失败:test_expect_success 'test three things' ' for i in one two three do test_something "$i" || return 1 done && test_something_else '请注意,我们仍然链接
&&循环以传播来自早期命令的失败。

