How to get the exit status a loop in bash

后端 未结 8 691
醉梦人生
醉梦人生 2020-12-16 15:38

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

相关标签:
8条回答
  • 2020-12-16 15:58

    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".

    See commit 7cc112d (27 Mar 2020) by Junio C Hamano (gitster).
    (Merged by Junio C Hamano -- gitster -- in commit b07c721, 28 Apr 2020)

    t/README: suggest how to leave test early with failure

    Helped-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/README to help developers writing new tests.

    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_something in 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 all test_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.

    0 讨论(0)
  • 2020-12-16 16:01

    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:

    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.

    0 讨论(0)
  • 2020-12-16 16:01

    I think what you should be asking is: How can I wait until a file or a directory (/test) gets created by another process?

    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 wrong by the standards of computer scientists.

    There are two remedies:

    1. 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).
    2. use a notification mechanism like inotify (see: man inotify); advantage: no CPU load, great responsiveness, no delays, no arbitrary constants in your code; disadvantage: inotify is a kernel API – you need some code to access it: inotify-tools or some C/Perl/Python code. Have a look at inotify and bash!
    0 讨论(0)
  • 2020-12-16 16:06

    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.

    0 讨论(0)
  • 2020-12-16 16:06

    Use artificial exit code

    0 讨论(0)
  • 2020-12-16 16:09

    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: $?" 
    
    0 讨论(0)
提交回复
热议问题