Bash set + x sin que se imprima

92

¿Alguien sabe si podemos decir set +xen bash sin que se imprima:

set -x
command
set +x

huellas

+ command
+ set +x

pero solo debería imprimir

+ command

Bash es la versión 4.1.10 (4). Esto me está molestando desde hace algún tiempo: la salida está llena de set +xlíneas inútiles , lo que hace que la función de rastreo no sea tan útil como podría ser.

Andreas Spindler
fuente
Esto no responde a su pregunta, pero cuando ejecuta su script, ¿por qué no?script.sh 2>&1 | grep -v 'set +x'
cdarke

Respuestas:

145

Tuve el mismo problema y pude encontrar una solución que no usa una subcapa:

set -x
command
{ set +x; } 2>/dev/null
McJoey
fuente
10
Excelente respuesta, solo una nota: sin un punto y coma después del comando, esto no funcionará; y con punto y coma pero sin espacios entre llaves, se generará un error de sintaxis.
sdaau
9
Esto pone a cero el estado de salida.
Garth Kidd
8
El estado de salida de @GarthKidd se pone a cero con cada comando exitoso. set +xes un comando tan exitoso
Daniel Alder
3
En los casos en que se necesita el estado de salida de command, esta variación es una solución: { STATUS=$?; set +x; } 2>/dev/null. Luego, inspeccione $STATUSen las siguientes líneas a su gusto.
Greg Price
5
Por otra parte, aquí está una versión golfed un poco más: { set +x; } 2>&-. Eso cierra fd 2 directamente en lugar de hacerlo apuntar a / dev / null. Algunos programas no se manejan tan bien cuando intentan imprimir en stderr, por lo que / dev / null es de buen estilo en general; pero el set -xtrazado del caparazón lo maneja bien, por lo que funciona perfectamente aquí, y hace que este encantamiento sea un poco más corto.
Greg Price
43

Puede utilizar una subshell. Al salir de la subcapa, xse perderá la configuración de :

( set -x ; command )
choroba
fuente
Bueno, gracias ... buen punto. De hecho, soy consciente del "truco del sub-caparazón". Esperaba que fuera más fácil que eso. Implica cambios sustanciales en el código, lo que hace que el código sea más complejo y menos legible. En mi humilde opinión, eso sería peor que vivir con el conjunto + líneas x ...
Andreas Spindler
No veo cómo ( set -x \n command \n )es peor que set -x \n command \n set +x.
chepner
3
@chepner: no puede establecer variables.
choroba
2
... y no puede cd: no cambia el directorio actual en el shell padre.
Andreas Spindler
Lo siento, no estoy seguro de cuál pensé que era su objeción real. Ha sido una semana larga ...
chepner
8

Hackeé una solución a esto recientemente cuando me molesté:

shopt -s expand_aliases
_xtrace() {
    case $1 in
        on) set -x ;;
        off) set +x ;;
    esac
}
alias xtrace='{ _xtrace $(cat); } 2>/dev/null <<<'

Esto le permite habilitar y deshabilitar xtrace como se muestra a continuación, donde estoy registrando cómo se asignan los argumentos a las variables:

xtrace on
ARG1=$1
ARG2=$2
xtrace off

Y obtienes una salida que se parece a:

$ ./script.sh one two
+ ARG1=one
+ ARG2=two
usuario108471
fuente
Truco inteligente (aunque no necesitas la /dev/stdinpieza). La advertencia es que activar la expansión de alias en los scripts puede tener efectos secundarios no deseados.
mklement0
Tienes razón. He editado la respuesta para eliminar lo superfluo /dev/stdin. No tengo conocimiento de ningún efecto secundario específico, ya que el entorno no interactivo no debería cargar ningún archivo que defina alias. ¿Qué efectos secundarios puede haber?
user108471
1
Ese es un buen punto: olvidé que los alias no se heredan, por lo que el riesgo es mucho menor de lo que pensaba (hipotéticamente, su secuencia de comandos podría estar obteniendo código de terceros que define los alias, pero estoy de acuerdo que probablemente no sea un real- preocupación mundial). +1
mklement0
1
@AndreasSpindler ¿Podría explicar por qué cree que es más probable que esta técnica filtre información más confidencial?
user108471
1
... básicamente porque los alias y las funciones son construcciones de alto nivel. set +xes mucho más difícil (si no imposible) comprometer. Pero sigue siendo una solución buena y directa, probablemente la mejor hasta ahora.
Andreas Spindler
7

¿Qué tal una solución basada en una versión simplificada de @ user108471:

shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ set +x; } 2>/dev/null'

trace_on
...stuff...
trace_off
Oliver
fuente
¿Qué tal esto? function () { set_plus_x='{ set +x; } 2>/dev/null' }
LexH
1

Esta es una combinación de algunas ideas que pueden incluir un bloque de código y preservar el estado de salida.

#!/bin/bash
shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ PREV_STATUS=$? ; set +x; } 2>/dev/null; (exit $PREV_STATUS)'

trace_on
echo hello
trace_off
echo "status: $?"

trace_on
(exit 56)
trace_off

Cuando se ejecuta:

$ ./test.sh 
+ echo hello
hello
status: 0
+ exit 56
status: 56

user3286792
fuente
Buen esfuerzo pero creo que la ()vuelta exitno es necesaria. Okay. Tal vez eso es paranoico, pero si este código se utiliza en general tiene una buena vía de ataque: redefinir trace_ony trace_offe inyectar código que lee los comandos ejecutados. Si usa tales "utilidades" solo es instructivo, pero si el código se usa con otros, debe considerar si los beneficios de tales funciones no estandarizadas superan las desventajas. Personalmente, me he conformado con { set +x; } 2>/dev/nullesta construcción que se entiende comúnmente y tampoco cambia el estado de salida.
Andreas Spindler