Make shopt change local to function

前端 未结 4 1861
渐次进展
渐次进展 2021-01-01 10:03

I\'m trying to write a bash function that uses nocasematch without changing the callers setting of the option. The function definition is:

is_he         


        
相关标签:
4条回答
  • 2021-01-01 10:31

    I know this post date from 2012, but you can also do the following (works in Git Bash 1.8.4 on Windows, so it should work on Linux) :

    function foobar() {
        local old=$(shopt -p extglob)
        shopt -s extglob
    
        ... your stuff here ...
        eval "$old"
    }
    

    The -p option simply print shopt -s extglob if extglob is on, otherwise shopt -u extglob.

    shopt -p print the whole list of options.

    0 讨论(0)
  • 2021-01-01 10:40

    Use a RETURN trap

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

    The -p option [to shopt] causes output to be displayed in a form that may be reused as input.

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

    foobar() {
        trap "$(shopt -p extglob)" RETURN
        shopt -s extglob
    
        # ... your stuff here ...
    
    }
    

    For test

    foobar() {
        trap "$(shopt -p extglob)" RETURN
        shopt -s extglob
    
        echo "inside foobar"
        shopt extglob # Display current setting for errexit option
    }
    
    main() {
        echo "inside main"
        shopt extglob # Display current setting for errexit option
        foobar
        echo "back inside main"
        shopt extglob # Display current setting for errexit option
    }
    

    Test

    $ main
    inside main
    extglob         off
    inside foobar
    extglob         on
    back inside main
    extglob         off
    

    Variation: To reset all shopt options, change the trap statement to:

    trap "$(shopt -p)" RETURN
    

    Variation: To reset all set options, change the trap statement to:

    trap "$(set +o)" RETURN
    

    Note: Starting with Bash 4.4, there's a better way: make $- local.

    Variation: To reset all set and all shopt options, change the trap statement to:

    trap "$(set +o)$(shopt -p)" RETURN
    

    NOTE: set +o is equivalent to shopt -p -o:

    +o Write the current option settings to standard output in a format that is suitable for reinput to the shell as commands that achieve the same options settings.

    – Open Group Base Specifications Issue 7, 2018 edition > set

    0 讨论(0)
  • 2021-01-01 10:40

    You can use an associative array to remember the previous setting and then use it for reverting to the earlier setting, like this:

    shopt_set

    declare -gA _shopt_restore
    shopt_set() {
        local opt count
        for opt; do
            if ! shopt -q "$opt"; then
                echo "$opt not set, setting it"
                shopt -s "$opt"
                _shopt_restore[$opt]=1
                ((count++))
            else
                echo "$opt set already"
            fi
        done
    }
    

    shopt_unset

    shopt_unset() {
        local opt restore_type
        for opt; do
            restore_type=${_shopt_restore[$opt]}
            if shopt -q "$opt"; then
                echo "$opt set, unsetting it"
                shopt -u "$opt"
                _shopt_restore[$opt]=2
            else
                echo "$opt unset already"
            fi
            if [[ $restore_type == 1 ]]; then
                unset _shopt_restore[$opt]
            fi
        done
    }
    

    shopt_restore

    shopt_restore() {
        local opt opts restore_type
        if (($# > 0)); then
            opts=("$@")
        else
            opts=("${!_shopt_restore[@]}")
        fi
        for opt in "${opts[@]}"; do
            restore_type=${_shopt_restore[$opt]}
            case $restore_type in
            1)
                echo "unsetting $opt"
                shopt -u "$opt"
                unset _shopt_restore[$opt]
                ;;
            2)
                echo "setting $opt"
                shopt -s "$opt"
                unset _shopt_restore[$opt]
                ;;
            *)
                echo "$opt wasn't changed earlier"
                ;;
            esac
        done
    }
    

    Then use these functions as:

    ... some logic ...
    shopt_set nullglob globstar      # set one or more shopt options
    ... logic that depends on the above shopt settings
    shopt_restore nullglob globstar  # we are done, revert back to earlier setting
    

    or

    ... some logic ...
    shopt_set nullglob
    ... some more logic ...
    shopt_set globstar
    ... some more logic involving shopt_set and shopt_unset ...
    shopt_restore             # restore everything
    

    Complete source code here: https://github.com/codeforester/base/blob/master/lib/shopt.sh

    0 讨论(0)
  • 2021-01-01 10:56

    The function body can be any compound command, not just a group command ( {} ). Use a sub-shell:

    is_hello_world() (
      shopt -s nocasematch
      [[ "$1" =~ "hello world" ]] 
    )
    
    0 讨论(0)
提交回复
热议问题