Quiero al set -x
principio de mi script y "deshacerlo" (volver al estado antes de configurarlo) después en lugar de configurarlo a ciegas +x
. es posible?
PD: ya he comprobado aquí ; eso no pareció responder a mi pregunta por lo que pude ver.
Para invertir un set -x
solo ejecute a set +x
. La mayoría de las veces, el reverso de una cadena set -str
es la misma cadena con un +
: set +str
.
En general, para restaurar todas las errexit
opciones de shell (lea a continuación sobre bash ) (cambiado con el set
comando) que podría hacer (también lea a continuación sobre las shopt
opciones de bash ):
oldstate="$(set +o); set -$-" # POSIXly store all set options.
.
.
set -vx; eval "$oldstate" # restore all options stored.
Este comando:
shopt -po xtrace
generará una cadena ejecutable que refleje el estado de la opción. La p
bandera significa imprimir, y la o
bandera especifica que estamos preguntando acerca de las opciones establecidas por el set
comando (a diferencia de las opciones establecidas por el shopt
comando). Puede asignar esta cadena a una variable y ejecutar la variable al final de su script para restaurar el 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 solución funciona para múltiples opciones simultáneamente:
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"
Agregar set +vx
evita la impresión de una larga lista de opciones.
Y, si no incluye nombres de opciones,
oldstate="$(shopt -po)"
te da los valores de todas las opciones. Y, si deja de lado la o
bandera, puede hacer lo mismo con las shopt
opciones:
# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"
# store state of all options.
oldstate="$(shopt -p)"
Si necesita probar si una set
opción está configurada, la forma más idiomática (Bash) de hacerlo es:
[[ -o xtrace ]]
que es mejor que las otras dos pruebas similares:
[[ $- =~ x ]]
[[ $- == *x* ]]
Con cualquiera de las pruebas, esto 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"
Aquí le mostramos cómo probar el estado de una shopt
opción:
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
Una solución simple y compatible con POSIX para almacenar todas las set
opciones es:
set +o
que se describe en el estándar POSIX como:
+ o
Escriba la configuración de opciones actual en la salida estándar en un formato que sea adecuado para reiniciar en el shell como comandos que logran la misma configuración de opciones.
Tan simplemente:
oldstate=$(set +o)
conservará los valores para todas las opciones establecidas con el set
comando
Nuevamente, restaurar las opciones a sus valores originales es cuestión de ejecutar la variable:
set +vx; eval "$oldstate"
Esto es exactamente equivalente a usar Bash's shopt -po
. Tenga en cuenta que no cubrirá todas las opciones posibles de Bash , ya que algunas de ellas están establecidas por shopt
.
Hay muchas otras opciones de shell enumeradas shopt
en 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
Esos podrían agregarse a la variable establecida anteriormente y restaurarse de la misma manera:
$ oldstate="$oldstate;$(shopt -p)"
.
. # change options as needed.
.
$ eval "$oldstate"
Es posible hacer ( $-
se adjunta para garantizar que errexit
se conserva):
oldstate="$(shopt -po; shopt -p); set -$-"
set +vx; eval "$oldstate" # use to restore all options.
Nota : cada shell tiene una forma ligeramente diferente de crear la lista de opciones que están configuradas o no (sin mencionar las diferentes opciones que están definidas), por lo que las cadenas no son portables entre shells, pero son válidas para el mismo shell.
zsh
También funciona correctamente (después de POSIX) desde la versión 5.3. En versiones anteriores, seguía a POSIX solo parcialmente, ya set +o
que imprimía las opciones en un formato que era adecuado para reintroducir en el shell como comandos, pero solo para las opciones establecidas (no imprimía las opciones no establecidas ).
El mksh (y, por consiguiente, lksh) todavía no puede (MIRBSD KSH R54 2016/11/11) hacer esto. El manual de mksh contiene esto:
En una versión futura, set + o se comportará conforme a POSIX e imprimirá comandos para restaurar las opciones actuales.
En bash, el valor de set -e
( errexit
) se restablece dentro de las subcapas, lo que hace que sea difícil capturar su valor set +o
dentro de una subcapa $ (...).
Como solución alternativa, use:
oldstate="$(set +o); set -$-"
Con el shell de Almquist y sus derivados ( dash
, NetBSD / FreeBSD sh
al menos) y bash
4.4 o superior, puede hacer que las opciones sean locales para una función con local -
(haga la $-
variable local si lo desea):
$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
Esto no se aplica a la procedencia archivos, pero se puede redefinir source
como source() { . "$@"; }
para evitar esto.
Con ksh88
, los cambios de opción son locales a la función de forma predeterminada. Con ksh93
, ese es solo el caso de las funciones definidas con la function f { ...; }
sintaxis (y el alcance es estático en comparación con el alcance dinámico utilizado en otros shells, incluido ksh88):
$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
En zsh
, eso se hace con la localoptions
opción:
$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace
POSIXY, puedes hacer:
case $- in
(*x*) restore=;;
(*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace
Sin embargo, algunos shells generarán un + 2> /dev/null
sobre la restauración (y verá el rastro de esa case
construcción, por supuesto, si set -x
ya estaba habilitado). Ese enfoque tampoco es reentrante (como si lo haces en una función que se llama a sí misma u otra función que usa el mismo truco).
Consulte https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh (ámbito local para variables y opciones para shells POSIX) para saber cómo implementar una pila que funcione alrededor de eso.
Con cualquier shell, puede usar subshells para limitar el alcance de las opciones
$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace
Sin embargo, eso limita el alcance de todo (variables, funciones, alias, redirecciones, directorio de trabajo actual ...), no solo las opciones.
oldstate=$(set +o)
es una forma más simple (y POSIX) de almacenar todas las opciones.pdksh
/mksh
(y otros derivados de pdksh) ozsh
dondeset +o
solo muestra las desviaciones de la configuración predeterminada. Eso funcionaría para bash / dash / yash pero no sería portátil.Puede leer la
$-
variable al principio para ver si-x
está configurada o no y luego guardarla en una variable, por ejemploDel manual de Bash :
fuente
En bash, $ SHELLOPTS se establece con las banderas que están activadas. Verifíquelo antes de encender xtrace, y reinicie xtrace solo si estaba apagado antes.
fuente
Solo para decir lo obvio, si
set -x
va a estar vigente durante la duración de la secuencia de comandos, y esto es solo una medida de prueba temporal (no debe ser parte permanente de la salida), invoque la secuencia de comandos con la-x
opción, por ejemplo,... o, cambie temporalmente el script (primera línea) para habilitar la salida de depuración agregando la
-x
opción:Me doy cuenta de que esto probablemente es un golpe demasiado amplio para lo que quieres, pero es la forma más simple y rápida de habilitar / deshabilitar, sin complicar demasiado el script con cosas temporales que probablemente querrás eliminar de todos modos (en mi experiencia).
fuente
Esto proporciona funciones para guardar y restaurar las marcas visibles a través del
$-
parámetro especial POSIX . Usamos lalocal
extensión para variables locales. En un script portátil compatible con POSIX, se utilizarían variables globales (sinlocal
palabra clave):Esto se usa de manera similar a cómo se guardan y restauran los indicadores de interrupción en el kernel de Linux:
Esto no funcionará para ninguna de las opciones extendidas que no están cubiertas en la
$-
variable.Me acabo de dar cuenta de que POSIX tiene lo que estaba buscando: el
+o
argumento deset
no es una opción, sino un comando que voltea un montón de comandos que, si soneval
restaurados, restaurarán las opciones. Entonces:Eso es.
Un pequeño problema es que si la
-x
opción se activa antes de estoeval
,set -o
se ve una desagradable ráfaga de comandos. Para eliminar esto, podemos hacer lo siguiente:fuente
Puedes usar un sub-shell.
fuente
Similar a lo que dijo @Jeff Shaller pero configurado para NO hacer eco de esa parte en el medio (que es lo que necesitaba):
fuente