如何获得退出状态在bash循环

我知道如何使用$?来检查之前执行的命令的状态,并且我们可以使用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. 

循环的状态是执行的最后一个命令的状态。 你可以使用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 

你也可以把循环放在一个函数中,并从中返回一个值。

像这样的东西?

 while true; do case $RANDOM in *0) exit 27 ;; esac done 

或者像这样?

 rc=0 for file in *; do grep fnord "$file" || rc=$? done exit $rc 

真正的问题是如果一次迭代失败,决定循环的退出代码是成功还是失败。 有些情况下,一个比另一个更有意义,而另外一些情况下,这个情况并不完全清楚。

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.[..] 

在循环内部执行的最后一个命令是breakbreak的出口值是0(请参阅: help break )。

这就是为什么你的程序保持0退出。

我想你应该问的是: 我如何等待,直到一个文件或目录( /test )由另一个进程创建?

到目前为止你所做的是全力投票。 您的循环将分配高达100%的核心处理能力。 关键字是“polling”,这是计算机科学家的标准在道德上是错误的。

有两种补救措施:

  1. 在你的循环中插入睡眠语句; 优点:非常简单; 缺点:延迟将是CPU负载和响应之间的任意折衷。 (“任意”也是道德错误的)。
  2. 使用类似inotify的通知机制(请参阅man inotify ); 优点:没有CPU负载,响应速度快,没​​有延迟,代码中没有任何常量; 缺点: inotify是一个内核API – 你需要一些代码来访问它: inotify-tools或者一些C / Perl / Python代码。 看看inotify和bash !

打破内置的bash确实可以让你完成你在做什么,只是打破了一个负值,由$返回状态? 将是1:

 while true do if [ -f "./test" ] ; then break -1 fi done echo $? ## You'll get 1 here.. 

请注意,这是内置break的帮助文档:

 help break 

break:break [n]退出,while或直到循环。

退出FOR,WHILE或UNTIL循环。 如果指定了N,则打破N封闭循环。

退出状态:退出状态为0,除非N不大于或等于1。

你可以跳出n个循环,或者发送一个非零值,即1

我同意@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