11

I'm writing a script that needs to be executed using source, because its task is to modify the environment. During the script, I want to use set -e so that any error stops the script. The script looks like this:

#!/bin/bash
set -e
# do something
cd somewhere
source anotherScript

The problem is that set -e naturally remains in effect after the script finishes. How can I ensure that the altered set option is properly restored to its prevous value when the script stops (in any way - either by completing successfully or on an error)?

Petr
  • 3,031
  • 7
  • 27
  • 45

4 Answers4

16

The command set +o lists the current settings as commands that restore the same state, e.g.

$ set +o
set +o allexport
set -o braceexpand
set -o emacs
set +o errexit
set +o errtrace
...

You can easily restore all the options later, if you save this output to a shell variable:

SAVED_OPTIONS=$(set +o)
set -e
# do something
eval "$SAVED_OPTIONS"

Bash includes also a number of non-standard (not POSIX) options that are adjusted using shopt command. The command shopt -p can be used to save these options in a similar fashion.

If you only want to save and restore one option, you can use the $- environment variable, which lists the current set of options as letters, e.g.

$ echo $-
himBH

You could use something like this to save and restore a particular option:

[[ $- = *e* ]]
SAVED_ERREXIT=$?
set -e
# do something
(( $SAVED_ERREXIT )) && set +e
Seppo Enarvi
  • 306
  • 2
  • 4
  • Note that it's very important not to miss the quotes around "$SAVED_OPTIONS" in the eval call. – Matt Jun 06 '18 at 16:47
3

Use a RETURN trap

RETURN traps work for sourced scripts, too.

Commands specified with an RETURN trap are executed before execution resumes after a shell function or a shell script executed with . or source returns.

https://www.gnu.org/software/bash/manual/bash.html

main_script.sh

#!/usr/bin/env bash
echo "inside main script"
shopt -o errexit
source a_script_to_be_sourced.sh
echo "back inside main script"
shopt -o errexit

a_script_to_be_sourced.sh

trap "$(shopt -p -o errexit)" RETURN
set -e # Equivalents: set -o errexit; shopt -s -o errexit
echo "inside sourced script"
shopt -o errexit

Test

$ ./main_script.sh 
inside main script
errexit         off
inside sourced script
errexit         on
back inside main script
errexit         off
3

Exactly the same way you activate it: calling the buitin set:

$ set -o errexit
$ set -o | grep errexit
errexit         on
$ set +o errexit
$ set -o | grep errexit
errexit         off

From the bash(1) manpage, under the SHELL BUILTIN COMMANDS section, `set' command:

-o option-name
The option-name can be one of the following:
    errexit Same as -e.
dawud
  • 1,450
  • 12
  • 18
  • 4
    Is there a way how to save (all) these settings and restore them later? – Petr Sep 21 '13 at 10:04
  • Run `set -o` to known your current setup. Be explicit when setting/unsetting any of them on your scripts. – dawud Sep 21 '13 at 10:12
2

Restoring previous activated settings can be quickly done as:

PREV_SETTING=$-  # e.g. himxBH  (there was xtrace)

set +x
# do your script without xtrace, ...

set -$PREV_SETTING

The other way around (restore to the off state) AFAIK there isn't such a shortcut and Seppo's answer covers all cases.

F Pereira
  • 121
  • 2
  • Your code as written yields `-bash: set: -i: invalid option` because the `-i` flag notes an interactive shell. – dpw Jul 08 '19 at 21:50