Description
Describe the feature/solution
When we need to change the shell options for certain operations, currently we save the original state using local reset=$(shopt -p nullglob)
, local reset=$(shopt -po noglob)
, etc. and then restore the state by $reset
. However, this requires the extra cost of creating a subshell. Can we think about switching to a more efficient way to save/restore shell options? Maybe there is no simple way to achieve it by only using the builtin features directly, but we might consider preparing special helper functions for this purpose.
This discussion derived from #687. Here the existing suggestions there are quoted:
store_options() { declare -n state=$1 shift for opt in $@ do shopt -q $opt && state[$opt]="-s" || state[$opt]="-u" done } restore_options() { declare -n state=$1 shift for opt in ${!state[@]} do shopt ${state[$opt]} $opt done } some_function() { declare -A opts set -x store_options opts localvar_unset restore_options opts set +x }What about this?
Maybe we can just save the value of
$BASHOPTS
, and then later test it using[[ :$saved_bashopts: == *:"$opt":* ]]
. This is actually what I do in my personal scripts._comp_restore_shopt() { local bashopts=$1; shift local opt for opt; do if [[ :$bashopts: == *:"$opt":* ]]; then shopt -s "$opt" else shopt -u "$opt" fi done } some_function() { local bashopts=$BASHOPTS set -x shopt -u localvar_unset _comp_restore_shopt "$bashopts" localvar_unset set +x }I like this approach overall, and it is straightforward. The only concern I have is that it is easy to forget an argument when calling
_comp_restore_shopt
. That could be avoided by looping over all options like this:_comp_restore_shopt() { local bashopts=$1; shift local IFS=: for opt in $BASHOPTS $bashopts; do if [[ :$bashopts: == *:"$opt":* ]]; then shopt -s "$opt" else shopt -u "$opt" fi done }I think this approach is likely not worth the loss of efficiency compared with your approach.
We can use the same approach for set
options using the special shell variable $-
or $SHELLOPTS
.
Note that Bash 4.4 supports local -
where set
options will be automatically restored when the control returns the function.
Edit: This discussion #352 (review) can also be related.