Chcę set -x
na początku skryptu i „cofnąć” go (wrócić do stanu, zanim go ustawię), zamiast ślepego ustawiania +x
. czy to możliwe?
PS: Już tu sprawdziłem ; to nie wydawało się odpowiadać na moje pytanie, o ile mogłem powiedzieć.
Chcę set -x
na początku skryptu i „cofnąć” go (wrócić do stanu, zanim go ustawię), zamiast ślepego ustawiania +x
. czy to możliwe?
PS: Już tu sprawdziłem ; to nie wydawało się odpowiadać na moje pytanie, o ile mogłem powiedzieć.
Odpowiedzi:
Aby odwrócić po set -x
prostu wykonaj a set +x
. Większość czasu, odwrotnością ciąg set -str
jest taki sam ciąg z +
: set +str
.
Ogólnie, aby przywrócić wszystkie errexit
opcje powłoki (czytaj poniżej o bash ) (zmienione za pomocą set
komendy), możesz zrobić (przeczytaj również o shopt
opcjach bash ):
oldstate="$(set +o); set -$-" # POSIXly store all set options.
.
.
set -vx; eval "$oldstate" # restore all options stored.
To polecenie:
shopt -po xtrace
wygeneruje łańcuch wykonywalny, który odzwierciedla stan opcji. Te p
środki flag wydrukować, a o
określa flag że pytamy o opcji (s) ustawianą przez set
komendy (w przeciwieństwie do opcji zestawu (ów) przez shopt
komendę). Możesz przypisać ten ciąg do zmiennej i wykonać zmienną na końcu skryptu, aby przywrócić stan początkowy.
# 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"
To rozwiązanie działa jednocześnie dla wielu opcji:
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"
Dodanie set +vx
pozwala uniknąć drukowania długiej listy opcji.
A jeśli nie podasz żadnych nazw opcji,
oldstate="$(shopt -po)"
daje wartości wszystkich opcji. A jeśli pominiesz o
flagę, możesz zrobić to samo z shopt
opcjami:
# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"
# store state of all options.
oldstate="$(shopt -p)"
Jeśli chcesz sprawdzić, czy set
opcja jest ustawiona, najbardziej idiomatycznym (Bash) sposobem jest:
[[ -o xtrace ]]
co jest lepsze niż dwa pozostałe podobne testy:
[[ $- =~ x ]]
[[ $- == *x* ]]
W przypadku dowolnego testu działa to:
# 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"
Oto jak przetestować stan shopt
opcji:
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
Proste, zgodne z POSIX rozwiązanie do przechowywania wszystkich set
opcji to:
set +o
który jest opisany w standardzie POSIX jako:
+ o
Zapisz bieżące ustawienia opcji na standardowe wyjście w formacie odpowiednim do ponownego włożenia do powłoki jako polecenia, które osiągają te same ustawienia opcji.
Po prostu:
oldstate=$(set +o)
zachowa wartości dla wszystkich opcji ustawionych za pomocą set
polecenia.
Ponownie przywrócenie opcji do ich oryginalnych wartości jest kwestią wykonania zmiennej:
set +vx; eval "$oldstate"
Jest to dokładnie równoważne z używaniem Basha shopt -po
. Pamiętaj, że nie obejmie wszystkich możliwych opcji Bash , ponieważ niektóre z nich są ustawione przez shopt
.
Istnieje wiele innych opcji powłoki wymienionych shopt
w 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
Można je dołączyć do powyższej zmiennej i przywrócić w ten sam sposób:
$ oldstate="$oldstate;$(shopt -p)"
.
. # change options as needed.
.
$ eval "$oldstate"
Można to zrobić (dodaje $-
się, aby zapewnić errexit
zachowanie):
oldstate="$(shopt -po; shopt -p); set -$-"
set +vx; eval "$oldstate" # use to restore all options.
Uwaga : każda powłoka ma nieco inny sposób na zbudowanie listy opcji, które są ustawione lub wyłączone (nie wspominając o różnych zdefiniowanych opcjach), więc łańcuchy nie są przenośne między powłokami, ale są ważne dla tej samej powłoki.
zsh
działa również poprawnie (zgodnie z POSIX) od wersji 5.3. W poprzednich wersjach tylko częściowo stosował się do POSIX-a set +o
, drukując opcje w formacie odpowiednim do ponownego wprowadzenia się do powłoki jako polecenia, ale tylko dla opcji ustawionych (nie drukował opcji nieustawionych ).
Program mksh (i w konsekwencji lksh) nie jest jeszcze (MIRBSD KSH R54 2016/11/11) w stanie to zrobić. Podręcznik mksh zawiera to:
W przyszłej wersji set + o zachowa zgodność z POSIX i wyda polecenia, aby zamiast tego przywrócić bieżące opcje.
W bash wartość set -e
( errexit
) jest resetowana wewnątrz podpowłoki, co utrudnia uchwycenie jej wartości za set +o
pomocą podpowłoki $ (…).
Aby obejść ten problem, użyj:
oldstate="$(set +o); set -$-"
Dzięki powłoce Almquist i jej pochodnym ( przynajmniej dash
NetBSD / FreeBSD sh
) i bash
4.4 lub nowszym możesz ustawić opcje lokalne dla funkcji za pomocą local -
(ustaw $-
zmienną lokalną, jeśli chcesz):
$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
Nie dotyczy to plików źródłowych , ale możesz przedefiniować source
sposób source() { . "$@"; }
obejścia tego.
Za ksh88
pomocą domyślnie zmiany opcji są lokalne dla funkcji. Z ksh93
, dotyczy to tylko funkcji zdefiniowanych przy pomocy function f { ...; }
składni (a zakres jest statyczny w porównaniu do zakresu dynamicznego używanego w innych powłokach, w tym ksh88):
$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
W zsh
to jest zrobione z localoptions
opcją:
$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace
POSIXly możesz:
case $- in
(*x*) restore=;;
(*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace
Jednak niektóre powłoki wygenerują a + 2> /dev/null
po przywróceniu (i oczywiście zobaczysz ślad tej case
konstrukcji, jeśli set -x
był już włączony). Podejście to również nie jest ponownie uruchamiane (tak jak w przypadku funkcji, która wywołuje samą siebie lub innej funkcji używającej tej samej sztuczki).
Zobacz https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh (lokalny zakres dla zmiennych i opcji dla powłok POSIX), aby dowiedzieć się, jak zaimplementować stos, który działa wokół tego.
W dowolnej powłoce można użyć podpowłoki, aby ograniczyć zakres opcji
$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace
Ogranicza to jednak zakres wszystkiego (zmiennych, funkcji, aliasów, przekierowań, bieżącego katalogu roboczego ...), nie tylko opcji.
oldstate=$(set +o)
jest to prostszy (i POSIX) sposób przechowywania wszystkich opcji.
pdksh
/ mksh
(i inne pochodne pdksh) lub zsh
gdzie set +o
wypisuje jedynie odchylenia od ustawień domyślnych. To działałoby dla bash / dash / yash, ale nie byłoby przenośne.
Możesz odczytać $-
zmienną na początku, aby sprawdzić, czy -x
jest ustawiona, czy nie, a następnie zapisać ją w zmiennej np
if [[ $- == *x* ]]; then
was_x_set=1
else
was_x_set=0
fi
Z podręcznika Bash :
($ -, łącznik.) Rozwija się do bieżących flag opcji określonych podczas wywołania za pomocą wbudowanego polecenia set lub tych ustawionych przez samą powłokę (na przykład opcję -i).
[[ $SHELLOPTS =~ xtrace ]] && wasset=1
set -x
echo rest of your script
[[ $wasset -eq 0 ]] && set +x
W bash $ SHELLOPTS jest ustawiony przy włączonych flagach. Sprawdź to przed włączeniem xtrace i zresetuj xtrace tylko, jeśli wcześniej był wyłączony.
Aby powiedzieć oczywiste, jeśli set -x
ma obowiązywać przez czas trwania skryptu, a jest to tylko tymczasowy środek testowy (nie powinien być trwale częścią wyniku), wówczas albo wywołaj skrypt bez -x
opcji, np.
$ bash -x path_to_script.sh
... lub tymczasowo zmień skrypt (pierwszy wiersz), aby włączyć wyjście debugowania, dodając -x
opcję:
#!/bin/bash -x
...rest of script...
Zdaję sobie sprawę, że prawdopodobnie jest to zbyt szeroki skok do tego, czego chcesz, ale jest to najprostszy i najszybszy sposób włączania / wyłączania, bez nadmiernego komplikowania skryptu tymczasowymi rzeczami, które prawdopodobnie i tak chcesz usunąć (z mojego doświadczenia).
Zapewnia to funkcje do zapisywania i przywracania flag widocznych poprzez $-
specjalny parametr POSIX . Używamy local
rozszerzenia dla zmiennych lokalnych. W przenośnym skrypcie zgodnym z POSIX używane byłyby zmienne globalne (bez local
słowa kluczowego):
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"}
}
Jest to używane podobnie do sposobu zapisywania i odtwarzania flag przerwań w jądrze 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 ... */
To nie zadziała dla żadnej z rozszerzonych opcji, które nie są uwzględnione w $-
zmiennej.
Właśnie zauważyłem, że POSIX ma to, czego szukałem: +o
argumentem set
nie jest opcja, ale polecenie, które zrzuca wiązkę poleceń, które jeśli eval
-ed przywróci opcje. Więc:
flags=$(set +o)
set -x
# ...
eval "$flags"
Otóż to.
Jednym małym problemem jest to, że jeśli -x
opcja zostanie wcześniej zmieniona eval
, pojawi się brzydka seria set -o
poleceń. Aby to wyeliminować, możemy wykonać następujące czynności:
set +x # turn off trace not to see the flurry of set -o.
eval "$flags" # restore flags
Możesz użyć podpowłoki.
(
set …
do stuff
)
Other stuff, that set does not apply to