Quero set -x
no início do meu script e "desfazer" (voltar ao estado antes de defini-lo) depois, em vez de definir cegamente +x
. Isso é possível?
PS: Eu já verifiquei aqui ; isso não parecia responder à minha pergunta até onde eu sabia.
Para reverter um set -x
basta executar a set +x
. Na maioria das vezes, o inverso de uma string set -str
é a mesma seqüência com um +
: set +str
.
Em geral, para restaurar todas as errexit
opções de shell (leia abaixo sobre o bash ) (alteradas com o set
comando), você pode fazer (também leia abaixo sobre as shopt
opções do bash ):
oldstate="$(set +o); set -$-" # POSIXly store all set options.
.
.
set -vx; eval "$oldstate" # restore all options stored.
Este comando:
shopt -po xtrace
irá gerar uma cadeia de caracteres executável que reflete o estado da opção. O p
sinalizador significa imprimir, e o o
sinalizador especifica que estamos perguntando sobre as opções definidas pelo set
comando (em oposição às opções definidas pelo shopt
comando). Você pode atribuir essa sequência a uma variável e executar a variável no final do seu script para restaurar o estado inicial.
# 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"
Esta solução funciona para várias opções simultaneamente:
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"
A adição set +vx
evita a impressão de uma longa lista de opções.
E, se você não listar nenhum nome de opção,
oldstate="$(shopt -po)"
fornece os valores de todas as opções. E, se você deixar de fora a o
bandeira, poderá fazer o mesmo com as shopt
opções:
# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"
# store state of all options.
oldstate="$(shopt -p)"
Se você precisar testar se uma set
opção está definida, a maneira mais idiomática (Bash) de fazer isso é:
[[ -o xtrace ]]
o que é melhor que os outros dois testes semelhantes:
[[ $- =~ x ]]
[[ $- == *x* ]]
Com qualquer um dos testes, isso funciona:
# 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"
Veja como testar o estado de uma shopt
opção:
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
Uma solução simples e compatível com POSIX para armazenar todas as set
opções é:
set +o
que é descrito no padrão POSIX como:
+ o
Escreva as configurações de opções atuais na saída padrão em um formato adequado para reinicialização no shell como comandos que atingem as mesmas configurações de opções.
Então, simplesmente:
oldstate=$(set +o)
preservará valores para todas as opções definidas usando o set
comando
Novamente, restaurar as opções para seus valores originais é uma questão de executar a variável:
set +vx; eval "$oldstate"
Isso é exatamente equivalente ao uso do Bash's shopt -po
. Observe que ele não cobrirá todas as opções possíveis do Bash , pois algumas delas são definidas por shopt
.
Há muitas outras opções do shell listados com shopt
no 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
Eles podem ser anexados à variável definida acima e restaurados da mesma maneira:
$ oldstate="$oldstate;$(shopt -p)"
.
. # change options as needed.
.
$ eval "$oldstate"
É possível fazer (o $-
é anexado para garantir a errexit
preservação):
oldstate="$(shopt -po; shopt -p); set -$-"
set +vx; eval "$oldstate" # use to restore all options.
Nota : cada shell possui uma maneira ligeiramente diferente de criar a lista de opções configuradas ou não (para não mencionar as opções diferentes definidas), portanto, as strings não são portáveis entre shells, mas são válidas para o mesmo shell.
zsh
também funciona corretamente (após o POSIX) desde a versão 5.3. Nas versões anteriores, seguia o POSIX apenas parcialmente, set +o
na medida em que imprimia opções em um formato adequado para reinicializar o shell como comandos, mas apenas para opções definidas (não imprimia opções não definidas ).
O mksh (e, consequentemente, lksh) ainda não é capaz (MIRBSD KSH R54 2016/11/11). O manual mksh contém:
Em uma versão futura, set + o comportará comandos compatíveis com POSIX e imprimirá para restaurar as opções atuais.
No bash, o valor de set -e
( errexit
) é redefinido dentro de subcascas, o que dificulta a captura de seu valor set +o
dentro de uma subcasca $ (…).
Como solução alternativa, use:
oldstate="$(set +o); set -$-"
Com o shell Almquist e seus derivados ( pelo menos dash
NetBSD / FreeBSD sh
) e bash
4.4 ou superior, você pode tornar as opções locais para uma função com local -
(torne a $-
variável local se desejar):
$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
Isso não se aplica a origem arquivos, mas você pode redefinir source
como source() { . "$@"; }
para trabalho em torno disso.
Com ksh88
, as alterações de opção são locais para a função por padrão. Com ksh93
, esse é apenas o caso das funções definidas com a function f { ...; }
sintaxe (e o escopo é estático comparado ao escopo dinâmico usado em outros shells, incluindo o ksh88):
$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
Em zsh
, isso é feito com a localoptions
opção:
$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace
POSIXly, você pode fazer:
case $- in
(*x*) restore=;;
(*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace
No entanto, alguns shells produzirão a + 2> /dev/null
após a restauração (e você verá o rastreio dessa case
construção, é claro, se set -x
já estiver ativado). Essa abordagem também não é reentrada (como se você fizer isso em uma função que se chama ou outra função que usa o mesmo truque).
Consulte https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh (escopo local para variáveis e opções para shells POSIX) para saber como implementar uma pilha que contorna isso.
Com qualquer shell, você pode usar subshells para limitar o escopo das opções
$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace
No entanto, isso limita o escopo de tudo (variáveis, funções, aliases, redirecionamentos, diretório de trabalho atual ...), não apenas opções.
oldstate=$(set +o)
é uma maneira mais simples (e POSIX) de armazenar todas as opções.pdksh
/mksh
(e outros derivados pdksh) ouzsh
ondeset +o
apenas gera os desvios das configurações padrão. Isso funcionaria para o bash / dash / yash, mas não seria portátil.Você pode ler a
$-
variável no início para ver se-x
está definida ou não e depois salvá-la em uma variável, por exemploNo manual do Bash :
fonte
No bash, $ SHELLOPTS é definido com os sinalizadores ativados. Verifique-o antes de ativar o xtrace e redefina o xtrace apenas se estiver desativado antes.
fonte
Apenas para declarar o óbvio, se
set -x
deve ter efeito durante a duração do script, e esta é apenas uma medida de teste temporária (para não fazer parte permanentemente da saída), invoque o script com a-x
opção, por exemplo,... ou, altere temporariamente o script (primeira linha) para ativar a saída de depuração adicionando a
-x
opção:Sei que isso provavelmente é um golpe muito amplo para o que você deseja, mas é a maneira mais simples e rápida de ativar / desativar, sem complicar demais o script com coisas temporárias que você provavelmente deseja remover de qualquer maneira (na minha experiência).
fonte
Isso fornece funções para salvar e restaurar os sinalizadores visíveis através do
$-
parâmetro especial POSIX . Usamos alocal
extensão para variáveis locais. Em um script portátil em conformidade com POSIX, variáveis globais seriam usadas (semlocal
palavra-chave):Isso é usado de maneira semelhante à maneira como os sinalizadores de interrupção são salvos e restaurados no kernel do Linux:
Isso não funcionará para nenhuma das opções estendidas que não são cobertas na
$-
variável.Acabei de notar que o POSIX tem o que eu estava procurando: o
+o
argumento deset
não é uma opção, mas um comando que despeja um monte de comandos que, seeval
-ed, restauram as opções. Assim:É isso aí.
Um pequeno problema é que, se a
-x
opção for ativada antes dissoeval
, um feio fluxo deset -o
comandos é visto. Para eliminar isso, podemos fazer o seguinte:fonte
Você pode usar um sub-shell.
fonte