Я хочу set -x
в начале своего сценария и «отменить» его (вернуться в состояние до того, как я его установлю) после установки вслепую +x
. Это возможно?
PS: я уже проверил здесь ; это, кажется, не отвечало на мой вопрос, насколько я мог сказать.
Я хочу set -x
в начале своего сценария и «отменить» его (вернуться в состояние до того, как я его установлю) после установки вслепую +x
. Это возможно?
PS: я уже проверил здесь ; это, кажется, не отвечало на мой вопрос, насколько я мог сказать.
Ответы:
Чтобы повернуть set -x
просто выполнить set +x
. Большая часть времени, обратные по отношению к строке set -str
одно и то же строка с +
: set +str
.
В общем, чтобы восстановить все (читайте ниже о bash errexit
) параметры оболочки (измененные с помощью set
команды), которые вы можете сделать (также читайте ниже о bash shopt
):
oldstate="$(set +o); set -$-" # POSIXly store all set options.
.
.
set -vx; eval "$oldstate" # restore all options stored.
Эта команда:
shopt -po xtrace
сгенерирует исполняемую строку, которая отражает состояние опции. На 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"
Это решение работает для нескольких вариантов одновременно:
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"
Добавление set +vx
позволяет избежать печати длинного списка опций.
И, если вы не перечислите имена опций,
oldstate="$(shopt -po)"
это дает вам значения всех вариантов. И, если вы оставите o
флаг, вы можете сделать то же самое с shopt
опциями:
# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"
# store state of all options.
oldstate="$(shopt -p)"
Если вам нужно проверить, установлена ли set
опция, самый идиоматический (Bash) способ сделать это:
[[ -o xtrace ]]
что лучше, чем два других похожих теста:
[[ $- =~ 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"
Вот как можно проверить состояние 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
Простое POSIX-совместимое решение для хранения всех set
опций:
set +o
который описан в стандарте POSIX как:
+ о
Запишите текущие настройки параметров в стандартный вывод в формате, подходящем для повторного ввода в оболочку, в качестве команд, которые достигают тех же настроек параметров.
Итак, просто:
oldstate=$(set +o)
сохранит значения для всех параметров, установленных с помощью set
команды.
Опять же, восстановление параметров до их исходных значений - это выполнение переменной:
set +vx; eval "$oldstate"
Это в точности эквивалентно использованию Bash shopt -po
. Обратите внимание, что он не охватывает все возможные параметры Bash , так как некоторые из них установлены shopt
.
В shopt
bash есть много других параметров оболочки :
$ 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
Они могут быть добавлены к указанной выше переменной и восстановлены таким же образом:
$ oldstate="$oldstate;$(shopt -p)"
.
. # change options as needed.
.
$ eval "$oldstate"
Это можно сделать ( $-
добавляется для обеспечения errexit
сохранения):
oldstate="$(shopt -po; shopt -p); set -$-"
set +vx; eval "$oldstate" # use to restore all options.
Примечание : каждая оболочка имеет немного другой способ построения списка параметров, которые установлены или не установлены (не говоря уже о различных параметрах, которые определены), поэтому строки не переносимы между оболочками, но действительны для одной и той же оболочки.
zsh
также работает правильно (в соответствии с POSIX) начиная с версии 5.3. В предыдущих версиях он следовал POSIX только частично, set +o
в том смысле, что он печатал параметры в формате, который был пригоден для повторного ввода в оболочку в качестве команд, но только для заданных параметров (он не печатал не заданные параметры).
Мкш (и, как следствие, лкш) пока не может (MIRBSD KSH R54 2016/11/11) сделать это. Инструкция МКШ содержит:
В будущей версии set + o будет вести себя как POSIX-совместимый и печатать команды для восстановления текущих параметров.
В bash значение set -e
( errexit
) сбрасывается внутри вложенных оболочек, что затрудняет захват его значения set +o
внутри вложенной оболочки $ (…).
В качестве обходного пути используйте:
oldstate="$(set +o); set -$-"
С помощью оболочки и производных Almquist ( по крайней мере dash
, NetBSD / FreeBSD sh
) и bash
4.4 или выше вы можете сделать опции локальными для функции с помощью local -
(сделайте $-
переменную локальной, если хотите):
$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
Это не относится к , источником файлов, но вы можете переопределить , source
как source() { . "$@"; }
работать вокруг этого.
При этом ksh88
изменения параметров являются локальными для функции по умолчанию. С ksh93
, это только в случае функций, определенных с function f { ...; }
синтаксисом (и область видимости является статической по сравнению с динамической областью видимости, используемой в других оболочках, включая ksh88):
$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
В zsh
, это сделано с localoptions
опцией:
$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace
POSIXly, вы можете сделать:
case $- in
(*x*) restore=;;
(*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace
Однако некоторые оболочки будут выводить + 2> /dev/null
при восстановлении (и вы , конечно, увидите след этой case
конструкции, если set -x
она уже была включена). Этот подход также не является повторным (например, если вы делаете это в функции, которая вызывает себя или другую функцию, которая использует тот же трюк).
См. Https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh (локальная область видимости для переменных и параметров для оболочек POSIX), чтобы узнать, как реализовать стек, который работает вокруг этого.
С любой оболочкой вы можете использовать подоболочки, чтобы ограничить область действия опций
$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace
Однако это ограничивает область действия всего (переменные, функции, псевдонимы, перенаправления, текущий рабочий каталог ...), а не только параметры.
oldstate=$(set +o)
это более простой (и POSIX) способ хранения всех опций.
pdksh
/ mksh
(и другие производные pdksh) или zsh
где выводятся set +o
только отклонения от настроек по умолчанию. Это будет работать для bash / dash / yash, но не будет переносимым.
Вы можете прочитать $-
переменную в начале, чтобы увидеть, -x
установлена она или нет, а затем сохранить ее в переменной, например.
if [[ $- == *x* ]]; then
was_x_set=1
else
was_x_set=0
fi
Из руководства Bash :
($ -, дефис.) Расширяется до флагов текущей опции, как указано при вызове, с помощью встроенной команды set или тех, которые установлены самой оболочкой (например, опция -i).
[[ $SHELLOPTS =~ xtrace ]] && wasset=1
set -x
echo rest of your script
[[ $wasset -eq 0 ]] && set +x
В bash $ SHELLOPTS устанавливается с включенными флагами. Проверьте это, прежде чем включать xtrace, и сбросьте xtrace, только если он был выключен ранее.
Просто чтобы заявить очевидное, если set -x
оно должно действовать в течение всего сценария, а это всего лишь временная мера тестирования (не быть постоянно частью вывода), то либо вызовите сценарий с -x
параметром, например,
$ bash -x path_to_script.sh
... или временно измените сценарий (первая строка), чтобы включить отладочный вывод, добавив -x
параметр:
#!/bin/bash -x
...rest of script...
Я понимаю, что это, вероятно, слишком широкий ход для того, что вы хотите, но это самый простой и быстрый способ включить / отключить, не слишком усложняя сценарий временными вещами, которые вы, вероятно, захотите удалить в любом случае (по моему опыту).
Это предоставляет функции для сохранения и восстановления флагов, которые видны через $-
специальный параметр POSIX . Мы используем local
расширение для локальных переменных. В переносимом скрипте, соответствующем POSIX, будут использоваться глобальные переменные (без local
ключевого слова):
save_opts()
{
echo $-
}
restore_opts()
{
local saved=$1
local on
local off=$-
while [ ${#saved} -gt 0 ] ; do
local rest=${saved#?}
local first=${saved%$rest}
if echo $off | grep -q $first ; then
off=$(echo $off | tr -d $first)
fi
on="$on$first"
saved=$rest
done
set ${on+"-$on"} ${off+"+$off"}
}
Это используется аналогично тому, как флаги прерываний сохраняются и восстанавливаются в ядре Linux:
Shell: Kernel:
flags=$(save_opts) long flags;
save_flags (flags);
set -x # or any other local_irq_disable(); /* disable irqs on this core */
# ... -x enabled ... /* ... interrupts disabled ... */
restore_opts $flags restore_flags(flags);
# ... x restored ... /* ... interrupts restored ... */
Это не будет работать ни для одной из расширенных опций, которые не включены в $-
переменную.
Просто заметил, что у POSIX есть то, что я искал: +o
аргумент set
не является опцией, а командой, которая выводит кучу команд, которые, если eval
-ed, восстановят опции. Так:
flags=$(set +o)
set -x
# ...
eval "$flags"
Вот и все.
Одна небольшая проблема заключается в том, что если -x
опция была включена до этого eval
, появляется ужасный поток set -o
команд. Чтобы устранить это, мы можем сделать следующее:
set +x # turn off trace not to see the flurry of set -o.
eval "$flags" # restore flags
Вы можете использовать вложенную оболочку.
(
set …
do stuff
)
Other stuff, that set does not apply to