Я хочу set -x
на початку свого сценарію і "скасувати" його (повернутись до стану, перш ніж я його встановити), а не сліпо налаштувати +x
. Чи можливо це?
PS: Я вже перевірив тут ; начебто я не відповів на моє запитання, наскільки я міг сказати.
Я хочу set -x
на початку свого сценарію і "скасувати" його (повернутись до стану, перш ніж я його встановити), а не сліпо налаштувати +x
. Чи можливо це?
PS: Я вже перевірив тут ; начебто я не відповів на моє запитання, наскільки я міг сказати.
Відповіді:
Для повернення set -x
просто виконувати a set +x
. Велика частина часу, зворотні по відношенню до рядка set -str
одне і те ж рядок з +
: set +str
.
Загалом, для відновлення всіх (читайте нижче про bash errexit
) параметрів оболонки (змінених set
командою) ви могли б зробити (також читайте нижче про shopt
параметри bash ):
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"
Це рівнозначно використанню Баша 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
оскільки він друкував параметри у форматі, який був придатний для повторного введення в оболонку як команди, але тільки для встановлених параметрів (він не друкував невстановлені параметри).
Mksh (і, як наслідок, lksh) ще не може (MIRBSD KSH R54 2016/11/11) це зробити. Посібник з mksh містить це:
У майбутній версії set + o буде поводитись сумісно з POSIX та друкувати команди для відновлення поточних параметрів.
В bash, значення set -e
( errexit
) скидається всередину під оболонок, що ускладнює захоплення його значення set +o
всередині $ (...) під оболонки.
В якості вирішення використовуйте:
oldstate="$(set +o); set -$-"
За допомогою оболонки Almquist та похідних ( dash
, sh
принаймні , NetBSD / FreeBSD ) та 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
Однак деякі оболонки видадуть a + 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 :
($ -, дефіс.) Розширюється на поточні прапори опцій, як зазначено при виклику, набором вбудованої команди або на ті, які встановлює сама оболонка (наприклад, опція -i).
[[ $SHELLOPTS =~ xtrace ]] && wasset=1
set -x
echo rest of your script
[[ $wasset -eq 0 ]] && set +x
В bash, $ SHELLOPTS встановлюється з увімкненими прапорами. Перевірте це, перш ніж увімкнути xtrace, і скиньте xtrace, лише якщо він був вимкнений раніше.
Просто заявіть про очевидне, якщо set -x
воно має діяти протягом тривалості сценарію, і це лише тимчасовий захід тестування (не бути постійною частиною виводу), а потім або викликати сценарій w / -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