我正在尝试编写一个使用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
的返回值,但这仍然意味着该函数应该记住这一点并在退出之前重置它。
答案 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)
在执行shell函数...返回...
之后执行恢复之前,执行使用RETURN陷阱指定的命令[shopt]的
-p
选项会使输出以可重复用作输入的形式显示。
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() {
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() {
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