What does set -e mean in a bash script?

后端 未结 8 878
醉酒成梦
醉酒成梦 2020-11-22 15:46

I\'m studying the content of this preinst file that the script executes before that package is unpacked from its Debian archive (.deb) file.

The scr

相关标签:
8条回答
  • 2020-11-22 16:10

    From help set :

      -e  Exit immediately if a command exits with a non-zero status.
    

    But it's considered bad practice by some (bash FAQ and irc freenode #bash FAQ authors). It's recommended to use:

    trap 'do_something' ERR
    

    to run do_something function when errors occur.

    See http://mywiki.wooledge.org/BashFAQ/105

    0 讨论(0)
  • 2020-11-22 16:10

    set -e stops the execution of a script if a command or pipeline has an error - which is the opposite of the default shell behaviour, which is to ignore errors in scripts. Type help set in a terminal to see the documentation for this built-in command.

    0 讨论(0)
  • 2020-11-22 16:10
    cat a.sh
    #! /bin/bash
    
    #going forward report subshell or command exit value if errors
    #set -e
    (cat b.txt)
    echo "hi"
    
    ./a.sh; echo $?
    cat: b.txt: No such file or directory
    hi
    0
    

    with set -e commented out we see that echo "hi" exit status being reported and hi is printed.

    cat a.sh
    #! /bin/bash
    
    #going forward report subshell or command exit value if errors
    set -e
    (cat b.txt)
    echo "hi"
    
    ./a.sh; echo $?
    cat: b.txt: No such file or directory
    1
    

    Now we see b.txt error being reported instead and no hi printed.

    So default behaviour of shell script is to ignore command errors and continue processing and report exit status of last command. If you want to exit on error and report its status we can use -e option.

    0 讨论(0)
  • 2020-11-22 16:19

    I believe the intention is for the script in question to fail fast.

    To test this yourself, simply type set -e at a bash prompt. Now, try running ls. You'll get a directory listing. Now, type lsd. That command is not recognized and will return an error code, and so your bash prompt will close (due to set -e).

    Now, to understand this in the context of a 'script', use this simple script:

    #!/bin/bash 
    # set -e
    
    lsd 
    
    ls
    

    If you run it as is, you'll get the directory listing from the ls on the last line. If you uncomment the set -e and run again, you won't see the directory listing as bash stops processing once it encounters the error from lsd.

    0 讨论(0)
  • 2020-11-22 16:21

    I found this post while trying to figure out what the exit status was for a script that was aborted due to a set -e. The answer didn't appear obvious to me; hence this answer. Basically, set -e aborts the execution of a command (e.g. a shell script) and returns the exit status code of the command that failed (i.e. the inner script, not the outer script).

    For example, suppose I have the shell script outer-test.sh:

    #!/bin/sh
    set -e
    ./inner-test.sh
    exit 62;
    

    The code for inner-test.sh is:

    #!/bin/sh
    exit 26;
    

    When I run outer-script.sh from the command line, my outer script terminates with the exit code of the inner script:

    $ ./outer-test.sh
    $ echo $?
    26
    
    0 讨论(0)
  • 2020-11-22 16:23

    As per bash - The Set Builtin manual, if -e/errexit is set, the shell exits immediately if a pipeline consisting of a single simple command, a list or a compound command returns a non-zero status.

    By default, the exit status of a pipeline is the exit status of the last command in the pipeline, unless the pipefail option is enabled (it's disabled by default).

    If so, the pipeline's return status of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.

    If you'd like to execute something on exit, try defining trap, for example:

    trap onexit EXIT
    

    where onexit is your function to do something on exit, like below which is printing the simple stack trace:

    onexit(){ while caller $((n++)); do :; done; }
    

    There is similar option -E/errtrace which would trap on ERR instead, e.g.:

    trap onerr ERR
    

    Examples

    Zero status example:

    $ true; echo $?
    0
    

    Non-zero status example:

    $ false; echo $?
    1
    

    Negating status examples:

    $ ! false; echo $?
    0
    $ false || true; echo $?
    0
    

    Test with pipefail being disabled:

    $ bash -c 'set +o pipefail -e; true | true | true; echo success'; echo $?
    success
    0
    $ bash -c 'set +o pipefail -e; false | false | true; echo success'; echo $?
    success
    0
    $ bash -c 'set +o pipefail -e; true | true | false; echo success'; echo $?
    1
    

    Test with pipefail being enabled:

    $ bash -c 'set -o pipefail -e; true | false | true; echo success'; echo $?
    1
    
    0 讨论(0)
提交回复
热议问题