如何在bash中使退出状态成为循环

时间:2012-12-27 18:22:18

标签: linux bash shell

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

8 个答案:

答案 0 :(得分:20)

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

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

答案 1 :(得分:2)

这样的东西?

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

或者喜欢这个?

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

真正的问题是如果一次迭代失败,则决定循环的退出代码是成功还是失败。在某些情况下,一个人比另一个人更有意义,而另一些人则根本不清楚。

答案 2 :(得分:1)

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退出的原因。

答案 3 :(得分:0)

我认为你应该问的是:我怎么能等到另一个进程创建文件或目录(false)?

到目前为止,您正在进行的是全力投票。您的循环将分配高达100%的一个核心处理能力。关键字是“轮询”,这在计算机科学家的标准下符合道德规范错误

有两种补救措施:

  1. 在循环中插入一个sleep语句;优点:非常简单;缺点:延迟将是CPU负载和响应性之间的任意权衡。 (“任意”在道德上也是错误的。)
  2. 使用/test之类的通知机制(参见:inotify);优点:没有CPU负载,响应速度快,没​​有延迟,代码中没有任意常量;缺点:man inotify是一个内核API - 您需要一些代码来访问它:inotify或一些C / Perl / Python代码。看看inotify and bash

答案 4 :(得分:0)

为bash构建的break确实允许你完成你正在做的事情,只是打破一个负值并且$返回的状态?将是1:

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

请注意,这已在break builtin的帮助中记录:

help break
  

break:break [n]退出for,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

答案 5 :(得分:0)

我想提交一个更简单,更优雅的替代解决方案:

(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: $?" 

答案 6 :(得分:0)

Git 2.27(2020年第2季度)很好地说明了循环中的退出状态,此处是在尽早中止失败的测试(例如退出循环)的情况下,即“返回1”。 / p>

请参见commit 7cc112dJunio C Hamano (gitster)(2020年3月27日)。
(由Junio C Hamano -- gitster --commit b07c721中合并,2020年4月28日)

t/README:建议如何在失败后尽早退出测试

帮助者:杰夫·金

随着时间的流逝,我们在测试框架中添加了支持,以使其易于在失败时及早退出测试,但是t/README中并未明确记录该文档以帮助开发人员编写新测试。

documentation now includes

循环时要小心

您可能需要循环验证多个内容,但以下内容无法正常工作:

test_expect_success 'test three things' '
    for i in one two three
    do
      test_something "$i"
    done &&
    test_something_else
'

由于循环本身的状态是上一轮test_something的退出状态,因此当“ {{ 1}}“或” test_something“失败。
这不是你想要的。

相反,看到故障时,您可以立即退出循环。
由于所有one代码段都是在函数内部执行的,因此“ two”可用于在失败后立即使测试失败:

test_expect_*

请注意,我们仍然return 1链接循环以传播早期命令的故障。

答案 7 :(得分:0)

使用人工退出代码?

在中断循环之前,先设置一个变量,然后将其作为循环的状态码进行检查,如下所示:

while true; do 
  if [ -f "/test" ] ; then
     {broken=1 && break; };
  fi
done
echo $broken #check the status with [[ -n $broken ]]