In a Bash script, how can I exit the entire script if a certain condition occurs?

后端 未结 7 1679
我在风中等你
我在风中等你 2020-11-29 14:30

I\'m writing a script in Bash to test some code. However, it seems silly to run the tests if compiling the code fails in the first place, in which case I\'ll just abort the

相关标签:
7条回答
  • 2020-11-29 14:52

    Instead of if construct, you can leverage the short-circuit evaluation:

    #!/usr/bin/env bash
    
    echo $[1+1]
    echo $[2/0]              # division by 0 but execution of script proceeds
    echo $[3+1]
    (echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
    echo $[5+1]
    

    Note the pair of parentheses which is necessary because of priority of alternation operator. $? is a special variable set to exit code of most recently called command.

    0 讨论(0)
  • 2020-11-29 14:53

    I have the same question but cannot ask it because it would be a duplicate.

    The accepted answer, using exit, does not work when the script is a bit more complicated. If you use a background process to check for the condition, exit only exits that process, as it runs in a sub-shell. To kill the script, you have to explicitly kill it (at least that is the only way I know).

    Here is a little script on how to do it:

    #!/bin/bash
    
    boom() {
        while true; do sleep 1.2; echo boom; done
    }
    
    f() {
        echo Hello
        N=0
        while
            ((N++ <10))
        do
            sleep 1
            echo $N
            #        ((N > 5)) && exit 4 # does not work
            ((N > 5)) && { kill -9 $$; exit 5; } # works 
        done
    }
    
    boom &
    f &
    
    while true; do sleep 0.5; echo beep; done
    

    This is a better answer but still incomplete a I really don't know how to get rid of the boom part.

    0 讨论(0)
  • 2020-11-29 14:59

    Use set -e

    #!/bin/bash
    
    set -e
    
    /bin/command-that-fails
    /bin/command-that-fails2
    

    The script will terminate after the first line that fails (returns nonzero exit code). In this case, command-that-fails2 will not run.

    If you were to check the return status of every single command, your script would look like this:

    #!/bin/bash
    
    # I'm assuming you're using make
    
    cd /project-dir
    make
    if [[ $? -ne 0 ]] ; then
        exit 1
    fi
    
    cd /project-dir2
    make
    if [[ $? -ne 0 ]] ; then
        exit 1
    fi
    

    With set -e it would look like:

    #!/bin/bash
    
    set -e
    
    cd /project-dir
    make
    
    cd /project-dir2
    make
    

    Any command that fails will cause the entire script to fail and return an exit status you can check with $?. If your script is very long or you're building a lot of stuff it's going to get pretty ugly if you add return status checks everywhere.

    0 讨论(0)
  • 2020-11-29 14:59

    I often include a function called run() to handle errors. Every call I want to make is passed to this function so the entire script exits when a failure is hit. The advantage of this over the set -e solution is that the script doesn't exit silently when a line fails, and can tell you what the problem is. In the following example, the 3rd line is not executed because the script exits at the call to false.

    function run() {
      cmd_output=$(eval $1)
      return_value=$?
      if [ $return_value != 0 ]; then
        echo "Command $1 failed"
        exit -1
      else
        echo "output: $cmd_output"
        echo "Command succeeded."
      fi
      return $return_value
    }
    run "date"
    run "false"
    run "date"
    
    0 讨论(0)
  • 2020-11-29 15:05

    If you will invoke the script with source, you can use return <x> where <x> will be the script exit status (use a non-zero value for error or false). But if you invoke an executable script (i.e., directly with its filename), the return statement will result in a complain (error message "return: can only `return' from a function or sourced script").

    If exit <x> is used instead, when the script is invoked with source, it will result in exiting the shell that started the script, but an executable script will just terminate, as expected.

    To handle either case in the same script, you can use

    return <x> 2> /dev/null || exit <x>
    

    This will handle whichever invocation may be suitable. That is assuming you will use this statement at the script's top level. I would advise against directly exiting the script from within a function.

    Note: <x> is supposed to be just a number.

    0 讨论(0)
  • 2020-11-29 15:06

    Try this statement:

    exit 1
    

    Replace 1 with appropriate error codes. See also Exit Codes With Special Meanings.

    0 讨论(0)
提交回复
热议问题