How to properly restore settings when running a script using "source"?

9

4

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 Pudlák

Posted 2013-09-21T07:33:27.823

Reputation: 2 197

http://stackoverflow.com/questions/29528624/how-to-restore-previous-set-x-option-in-bash – Ciro Santilli 新疆改造中心法轮功六四事件 – 2016-08-24T16:38:45.410

The same issue (for the -x / xtrace option)  is addressed at Suppress execution trace for echo command?

– Scott – 2018-11-02T00:28:02.773

Answers

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

Posted 2013-09-21T07:33:27.823

Reputation: 1 305

3Is there a way how to save (all) these settings and restore them later? – Petr Pudlák – 2013-09-21T10:04:31.113

Run set -o to known your current setup. Be explicit when setting/unsetting any of them on your scripts. – dawud – 2013-09-21T10:12:36.360

13

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

Posted 2013-09-21T07:33:27.823

Reputation: 276

Note that it's very important not to miss the quotes around "$SAVED_OPTIONS" in the eval call. – Matt – 2018-06-06T16:47:58.960

2

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

Robin A. Meade

Posted 2013-09-21T07:33:27.823

Reputation: 141

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

Posted 2013-09-21T07:33:27.823

Reputation: 121

Your code as written yields -bash: set: -i: invalid option because the -i flag notes an interactive shell. – dpw – 2019-07-08T21:50:40.807