What does set -e mean in a bash script?

后端 未结 8 879
醉酒成梦
醉酒成梦 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:24

    This is an old question, but none of the answers here discuss the use of set -e aka set -o errexit in Debian package handling scripts. The use of this option is mandatory in these scripts, per Debian policy; the intent is apparently to avoid any possibility of an unhandled error condition.

    What this means in practice is that you have to understand under what conditions the commands you run could return an error, and handle each of those errors explicitly.

    Common gotchas are e.g. diff (returns an error when there is a difference) and grep (returns an error when there is no match). You can avoid the errors with explicit handling:

    diff this that ||
      echo "$0: there was a difference" >&2
    grep cat food ||
      echo "$0: no cat in the food" >&2
    

    (Notice also how we take care to include the current script's name in the message, and writing diagnostic messages to standard error instead of standard output.)

    If no explicit handling is really necessary or useful, explicitly do nothing:

    diff this that || true
    grep cat food || :
    

    (The use of the shell's : no-op command is slightly obscure, but fairly commonly seen.)

    Just to reiterate,

    something || other
    

    is shorthand for

    if something; then
        : nothing
    else
        other
    fi
    

    i.e. we explicitly say other should be run if and only if something fails. The longhand if (and other shell flow control statements like while, until) is also a valid way to handle an error (indeed, if it weren't, shell scripts with set -e could never contain flow control statements!)

    And also, just to be explicit, in the absence of a handler like this, set -e would cause the entire script to immediately fail with an error if diff found a difference, or if grep didn't find a match.

    On the other hand, some commands don't produce an error exit status when you'd want them to. Commonly problematic commands are find (exit status does not reflect whether files were actually found) and sed (exit status won't reveal whether the script received any input or actually performed any commands successfully). A simple guard in some scenarios is to pipe to a command which does scream if there is no output:

    find things | grep .
    sed -e 's/o/me/' stuff | grep ^
    

    It should be noted that the exit status of a pipeline is the exit status of the last command in that pipeline. So the above commands actually completely mask the status of find and sed, and only tell you whether grep finally succeeded.

    (Bash, of course, has set -o pipefail; but Debian package scripts cannot use Bash features. The policy firmly dictates the use of POSIX sh for these scripts, though this was not always the case.)

    In many situations, this is something to separately watch out for when coding defensively. Sometimes you have to e.g. go through a temporary file so you can see whether the command which produced that output finished successfully, even when idiom and convenience would otherwise direct you to use a shell pipeline.

    0 讨论(0)
  • 2020-11-22 16:27
    Script 1: without setting -e
    #!/bin/bash
    decho "hi"
    echo "hello"
    This will throw error in decho and program continuous to next line
    
    Script 2: With setting -e
    #!/bin/bash
    set -e
    decho "hi" 
    echo "hello"
    # Up to decho "hi" shell will process and program exit, it will not proceed further
    
    0 讨论(0)
提交回复
热议问题