Cuando estás cerca de tu cuello en caimanes, es fácil olvidar que el objetivo era drenar el pantano.
- dicho popular
La pregunta es sobre echo
, y sin embargo, la mayoría de las respuestas hasta ahora se han centrado en cómo introducir un set +x
comando. Hay una solución mucho más simple y directa:
{ echo "Message"; } 2> /dev/null
(Reconozco que podría no haber pensado en { …; } 2> /dev/null
eso si no lo hubiera visto en las respuestas anteriores).
Esto es algo engorroso, pero, si tiene un bloque de echo
comandos consecutivos , no necesita hacerlo en cada uno individualmente:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Tenga en cuenta que no necesita punto y coma cuando tiene líneas nuevas.
Puede reducir la carga de escritura utilizando la idea
de kenorb de abrir /dev/null
permanentemente en un descriptor de archivo no estándar (por ejemplo, 3) y luego decir en 2>&3
lugar de 2> /dev/null
todo el tiempo.
Las primeras cuatro respuestas al momento de escribir esto requieren hacer algo especial (y, en la mayoría de los casos, engorroso)
cada vez que haces una echo
. Si realmente desea que todos los echo
comandos supriman la traza de ejecución (¿y por qué no lo haría?), Puede hacerlo globalmente, sin mezclar mucho código. Primero, noté que no se rastrean los alias:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Tenga en cuenta que los siguientes fragmentos de script funcionan si shebang es #!/bin/sh
, incluso si /bin/sh
es un enlace a bash. Pero, si es shebang #!/bin/bash
, debe agregar un shopt -s expand_aliases
comando para que los alias funcionen en un script).
Entonces, para mi primer truco:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Ahora, cuando decimos echo "Message"
, estamos llamando al alias, que no se rastrea. El alias desactiva la opción de rastreo, mientras suprime el mensaje de rastreo del set
comando (utilizando la técnica presentada primero en la respuesta del usuario 5071535 ) y luego ejecuta el echo
comando real . Esto nos permite obtener un efecto similar al de la respuesta del usuario 5071535 sin necesidad de editar el código en cada echo
comando. Sin embargo, esto deja el modo de rastreo desactivado. No podemos poner un set -x
en el alias (o al menos no fácilmente) porque un alias solo permite que una cadena sea sustituida por una palabra; ninguna parte de la cadena de alias se puede inyectar en el comando
después de los argumentos (por ejemplo, "Message"
). Entonces, por ejemplo, si el script contiene
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
la salida sería
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
así que aún necesita volver a activar la opción de rastreo después de mostrar los mensajes, pero solo una vez después de cada bloque de echo
comandos consecutivos :
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Sería bueno si pudiéramos hacer la set -x
automática después de un echo
- y podemos hacerlo , con un poco más de trucos. Pero antes de presentar eso, considere esto. El OP comienza con scripts que usan #!/bin/sh -ex
shebang. Implícitamente, el usuario podría eliminar el x
archivo shebang y tener un script que funcione normalmente, sin rastreo de ejecución. Sería bueno si pudiéramos desarrollar una solución que conserve esa propiedad. Las primeras respuestas aquí fallan esa propiedad porque activan el rastreo "de regreso" después de las echo
declaraciones, incondicionalmente, sin tener en cuenta si ya estaba activado.
Esta respuesta no reconoce ese problema, ya que reemplaza echo
salida con salida de rastreo; por lo tanto, todos los mensajes desaparecen si el rastreo está desactivado. Ahora presentaré una solución que activa el rastreo después de una echo
declaración condicionalmente , solo si ya estaba activada. Reducir esto a una solución que activa el rastreo "incondicionalmente" es trivial y se deja como un ejercicio.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-
es la lista de opciones; una concatenación de las letras correspondientes a todas las opciones que se configuran. Por ejemplo, si las opciones e
y x
están configuradas, $-
habrá un revoltijo de letras que incluye e
y x
. Mi nuevo alias (arriba) guarda el valor de $-
antes de desactivar el rastreo. Luego, con el rastreo desactivado, arroja el control a una función de shell. Esa función hace lo real echo
y luego verifica si la x
opción estaba activada cuando se invocó el alias. Si la opción estaba activada, la función la vuelve a activar; si estaba apagado, la función lo deja.
Puede insertar las siete líneas anteriores (ocho, si incluye una shopt
) al comienzo del guión y dejar el resto solo.
Esto te permitiría
- para usar cualquiera de las siguientes líneas shebang:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / sh –x
o simplemente#! / bin / sh
y debería funcionar como se esperaba.
- tener un código como
(shebang)
comando 1
comando 2
comando 3
set -x
comando 4
comando 5
comando 6
conjunto + x
comando 7
comando 8
comando 9
y
- Los comandos 4, 5 y 6 se rastrearán, a menos que uno de ellos sea un
echo
, en cuyo caso se ejecutará pero no se rastreará. (Pero incluso si el comando 5 es un echo
, el comando 6 aún se rastreará).
- Los comandos 7, 8 y 9 no se rastrearán. Incluso si el comando 8 es un
echo
, el comando 9 todavía no se rastreará.
- Los comandos 1, 2 y 3 se rastrearán (como 4, 5 y 6) o no (como 7, 8 y 9) dependiendo de si el shebang incluye
x
.
PD: He descubierto que, en mi sistema, puedo omitir la builtin
palabra clave en mi respuesta intermedia (la que es solo un alias echo
). Esto no es sorprendente; bash (1) dice que, durante la expansión de alias, ...
... una palabra que es idéntica a un alias que se expande no se expande por segunda vez. Esto significa que uno puede alias ls
de ls -F
, por ejemplo, y bash no intenta expandir recursivamente el texto de reemplazo.
No es sorprendente que la última respuesta (la que tiene echo_and_restore
) falle si builtin
se omite la palabra clave 1 . Pero, curiosamente, funciona si borro builtin
y cambio el orden:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Parece dar lugar a un comportamiento indefinido. He visto
- un bucle infinito (probablemente debido a una recursión ilimitada),
- un
/dev/null: Bad address
mensaje de error y
- un basurero
echo +x; echo "$*"; echo -x
un alias, me gustaría verlo.