使shopt改变本地功能

时间:2012-08-29 13:56:17

标签: bash shopt

我正在尝试编写一个使用nocasematch的bash函数,而不更改该选项的调用者设置。函数定义是:

is_hello_world() {
  shopt -s nocasematch
  [[ "$1" =~ "hello world" ]] 
}

在我打电话之前:

$ shopt nocasematch
nocasematch     off

称之为:

$ is_hello_world 'hello world' && echo Yes
Yes
$ is_hello_world 'Hello World' && echo Yes
Yes

正如预期的那样,但现在呼叫者的nocasematch发生了变化:

$ shopt nocasematch
nocasematch     on

有没有简单的方法让选项更改为函数的本地?

我知道我可以检查shopt -q的返回值,但这仍然意味着该函数应该记住这一点并在退出之前重置它。

4 个答案:

答案 0 :(得分:28)

函数体可以是任何复合命令,而不仅仅是组命令({})。使用子shell:

is_hello_world() (
  shopt -s nocasematch
  [[ "$1" =~ "hello world" ]] 
)

答案 1 :(得分:11)

我知道2012年的这个发布日期,但您也可以执行以下操作(适用于Windows上的Git Bash 1.8.4,因此它适用于Linux):

function foobar() {
    local old=$(shopt -p extglob)
    shopt -s extglob

    ... your stuff here ...
    eval "$old"
}

如果-p已开启,则shopt -s extglob选项只需打印extglob,否则为shopt -u extglob

shopt -p打印整个选项列表。

答案 2 :(得分:3)

使用RETURN陷阱

  

在执行shell函数...返回...

之后执行恢复之前,执行使用RETURN陷阱指定的命令      

[shopt]的-p选项会使输出以可重复用作输入的形式显示。

     

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

foobar() {
    trap "$(shopt -p extglob)" RETURN
    shopt -s extglob

    # ... your stuff here ...

}

进行测试

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
}

<强>测试

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

变体:要重置 所有商店 选项,请将trap语句更改为:

trap "$(shopt -p)" RETURN

变体要重置 所有设置 选项,请将trap语句更改为:

trap "$(set +o)" RETURN

注意:从Bash 4.4开始,有一种更好的方法:make $- local

变体要重置 所有设置 所有商店 选项,请更改陷阱语句:

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

注意: set +o相当于shopt -p -o

  

+ o 将当前选项设置以适合重新输入shell的格式写入标准输出,作为实现相同选项设置的命令。

     

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

答案 3 :(得分:2)

您可以使用关联数组来记住先前的设置,然后将其用于还原为先前的设置,如下所示:

购物集

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
}

然后将这些功能用作:

... 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

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

在此处完整源代码:https://github.com/codeforester/base/blob/master/lib/shopt.sh