ImH*_*ere 72
要反转 aset -x只需执行 a set +x。大多数情况下,字符串的反转set -str是带有+:的相同字符串set +str。
一般来说,要恢复所有(阅读下面关于 bash 的errexit)shell 选项(用set命令更改)你可以做(也阅读下面关于 bashshopt选项的内容):
oldstate="$(set +o)" # POSIXly store all set options.
.
.
set -vx; eval "$oldstate" # restore all options stored.
Run Code Online (Sandbox Code Playgroud)
应该足够了,但是 bash 有两组通过set(或shopt -po)访问的选项和通过shopt -p. 此外,bash 不会set -e在进入子 shell 时保留(errexit)。请注意,扩展产生的选项列表$-可能无法重新输入 shell。
要捕获整个当前状态(在 bash 中),请使用:
oldstate="$(shopt -po; shopt -p)"; [[ -o errexit ]] && oldstate="$oldstate; set -e"
Run Code Online (Sandbox Code Playgroud)
或者,如果您不介意设置inherit_errexit标志(并且您的 bash 是 ?4.4):
shopt -s inherit_errexit; oldstate="$(shopt -po; shopt -p)"
Run Code Online (Sandbox Code Playgroud)
这个命令:
shopt -po xtrace
Run Code Online (Sandbox Code Playgroud)
用于生成反映选项状态的可执行字符串。该p标志表示打印,该o标志指定我们正在询问由set命令设置的选项(而不是仅由shopt命令设置的选项)。您可以将此字符串分配给一个变量,并在脚本末尾执行该变量以恢复初始状态。
# store state of xtrace option.
tracestate="$(shopt -po xtrace)"
# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"
# restore the value of xtrace to its original value.
eval "$tracestate"
Run Code Online (Sandbox Code Playgroud)
此解决方案也同时适用于多个选项:
oldstate="$(shopt -po xtrace noglob errexit)"
# change options as needed
set -x
set +x
set -f
set -e
set -x
# restore to recorded state:
set +vx; eval "$oldstate"
Run Code Online (Sandbox Code Playgroud)
添加set +vx可避免打印一长串选项。
如果您没有列出任何选项名称,
oldstate="$(shopt -po)"
Run Code Online (Sandbox Code Playgroud)
它为您提供所有(设置)选项的值。而且,如果你省略了o标志,你可以用shopt选项做同样的事情:
# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"
# store state of all options.
oldstate="$(shopt -p)"
Run Code Online (Sandbox Code Playgroud)
如果您需要测试是否set设置了一个选项,最惯用的 (Bash) 方法是:
[[ -o xtrace ]]
Run Code Online (Sandbox Code Playgroud)
这比其他两个类似的测试要好:
[[ $- =~ x ]][[ $- == *x* ]]对于任何测试,这都有效:
# record the state of the xtrace option in ts (tracestate):
[ -o xtrace ] && ts='set -x' || ts='set +x'
# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"
# set the xtrace option back to what it was.
eval "$ts"
Run Code Online (Sandbox Code Playgroud)
以下是测试shopt选项状态的方法:
if shopt -q dotglob
then
# dotglob is set, so “echo .* *” would list the dot files twice.
echo *
else
# dotglob is not set. Warning: the below will list “.” and “..”.
echo .* *
fi
Run Code Online (Sandbox Code Playgroud)
一个简单的、符合 POSIX 标准的存储所有set选项的解决方案是:
set +o
Run Code Online (Sandbox Code Playgroud)
这是在POSIX标准描述如下:
+o
将当前选项设置以适合作为实现相同选项设置的命令重新输入到 shell 的格式写入标准输出。
所以,简单地说:
oldstate=$(set +o)
Run Code Online (Sandbox Code Playgroud)
将保留使用该set命令设置的所有选项的值(在某些 shell 中)。
同样,将选项恢复为其原始值是执行变量的问题:
set +vx; eval "$oldstate"
Run Code Online (Sandbox Code Playgroud)
这完全等同于使用 Bash 的shopt -po. 请注意,它不会涵盖所有可能的Bash选项,因为其中一些选项(仅)由shopt.
shopt在 bash 中列出了许多其他 shell 选项:
$ shopt
autocd off
cdable_vars off
cdspell off
checkhash off
checkjobs off
checkwinsize on
cmdhist on
compat31 off
compat32 off
compat40 off
compat41 off
compat42 off
compat43 off
complete_fullquote on
direxpand off
dirspell off
dotglob off
execfail off
expand_aliases on
extdebug off
extglob off
extquote on
failglob off
force_fignore on
globasciiranges off
globstar on
gnu_errfmt off
histappend on
histreedit off
histverify on
hostcomplete on
huponexit off
inherit_errexit off
interactive_comments on
lastpipe on
lithist off
login_shell off
mailwarn off
no_empty_cmd_completion off
nocaseglob off
nocasematch off
nullglob off
progcomp on
promptvars on
restricted_shell off
shift_verbose off
sourcepath on
xpg_echo off
Run Code Online (Sandbox Code Playgroud)
这些可以附加到上面设置的变量并以相同的方式恢复:
$ oldstate="$oldstate;$(shopt -p)"
.
. # change options as needed.
.
$ eval "$oldstate"
Run Code Online (Sandbox Code Playgroud)
set -e特殊情况在 bash 中,set -e( errexit)的值在子 shell 中被重置,这使得很难set +o在 $(...) 子 shell 中捕获它的值。
作为解决方法,请使用:
oldstate="$(set +o)"; [[ -o errexit ]] && oldstate="$oldstate; set -e"
Run Code Online (Sandbox Code Playgroud)
或者(如果它与您的目标不矛盾并且您的 bash 支持它)您可以使用该inherit_errexit选项。
注意:每个 shell 构建已设置或未设置的选项列表的方式略有不同(更不用说定义的不同选项),因此字符串在 shell 之间不可移植,但对同一个 shell 有效。
zsh从 5.3 版开始也可以正常工作(遵循 POSIX)。在以前的版本中,它仅部分遵循 POSIX set +o,因为它以适合作为命令重新输入到 shell 的格式打印选项,但仅用于设置选项(它不打印未设置的选项)。
mksh(以及相应的 lksh)还不能(MIRBSD KSH R54 2016/11/11)能够做到这一点。mksh 手册包含以下内容:
在未来的版本中, set +o 将按照 POSIX 标准执行并打印命令来恢复当前选项。
Sté*_*las 24
使用 Almquist shell 和衍生物(至少是dashNetBSD/FreeBSD sh)和 bash4.4 或更高版本,您可以使用以下方法将选项设置为函数的本地选项local -($-如果您愿意,可以将变量设置为本地):
$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
Run Code Online (Sandbox Code Playgroud)
这并不适用于采购文件,但你可以重新定义source为source() { . "$@"; }工作解决这一问题。
使用ksh88,默认情况下选项更改是函数的本地更改。使用ksh93,这只是使用function f { ...; }语法定义的函数的情况(与包括 ksh88 在内的其他 shell 中使用的动态范围相比,范围是静态的):
$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
Run Code Online (Sandbox Code Playgroud)
在 中zsh,这是通过localoptions选项完成的:
$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace
Run Code Online (Sandbox Code Playgroud)
POSIXly,你可以这样做:
case $- in
(*x*) restore=;;
(*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace
Run Code Online (Sandbox Code Playgroud)
然而,一些炮弹将输出+ 2> /dev/null时的恢复(你会看到痕迹是的case,当然,如果结构set -x已经启用)。这种方法也不是可重入的(就像在调用自身的函数或使用相同技巧的另一个函数中那样)。
请参阅https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh(POSIX shell 的变量和选项的本地范围),了解如何实现解决该问题的堆栈。
对于任何外壳,您都可以使用子外壳来限制选项的范围
$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace
Run Code Online (Sandbox Code Playgroud)
但是,这限制了所有内容(变量、函数、别名、重定向、当前工作目录...)的范围,而不仅仅是选项。
小智 13
您可以$-在开头读取变量以查看是否-x已设置,然后将其保存到变量中,例如
if [[ $- == *x* ]]; then
was_x_set=1
else
was_x_set=0
fi
Run Code Online (Sandbox Code Playgroud)
从Bash 手册:
($-,连字符。)扩展到当前选项标志,如调用时指定的、由 set 内置命令或由 shell 本身设置的(例如 -i 选项)。
[[ $SHELLOPTS =~ xtrace ]] && wasset=1
set -x
echo rest of your script
[[ $wasset -eq 0 ]] && set +x
Run Code Online (Sandbox Code Playgroud)
在 bash 中,$SHELLOPTS设置为打开的标志。在打开 xtrace 之前检查它,只有在它之前关闭时才重置 xtrace。
只是为了说明显而易见的,如果set -x要在脚本的持续时间内生效,并且这只是一个临时测试措施(不是永久的输出的一部分),那么要么调用带有-x选项的脚本,例如,
$ bash -x path_to_script.sh
Run Code Online (Sandbox Code Playgroud)
...或者,通过添加-x选项临时更改脚本(第一行)以启用调试输出:
#!/bin/bash -x
...rest of script...
Run Code Online (Sandbox Code Playgroud)
我意识到这对于您想要的东西来说可能过于宽泛,但它是启用/禁用的最简单和最快的方法,而不会使脚本过于复杂,而您可能无论如何都想删除这些临时内容(以我的经验)。