Cómo hacer eco de los comandos de shell a medida que se ejecutan

913

En un script de shell, ¿cómo hago eco de todos los comandos de shell llamados y expando los nombres de variables?

Por ejemplo, dada la siguiente línea:

ls $DIRNAME

Me gustaría que el script ejecute el comando y muestre lo siguiente

ls /full/path/to/some/dir

El propósito es guardar un registro de todos los comandos de shell llamados y sus argumentos. ¿Existe tal vez una mejor manera de generar tal registro?

Jack Nock
fuente

Respuestas:

1044

set -xo set -o xtraceexpande variables e imprime un pequeño signo + antes de la línea.

set -vo set -o verboseno expande las variables antes de imprimir.

Use set +xy set +vpara desactivar la configuración anterior.

En la primera línea del guión, se puede poner #!/bin/sh -x(o -v) para tener el mismo efecto que set -x(o -v) más adelante en el guión.

Lo anterior también funciona con /bin/sh.

Vea la wiki de bash-hackers sobre setatributos y depuración .

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so
$
Tom
fuente
77
Si también desea ver qué línea numerada se está ejecutando, consulte stackoverflow.com/a/17805088/1729501
user13107
3
¿Qué sucede si quiero colorear el comando cuando hago eco para diferenciar el comando y la salida de sus resultados?
Lewis Chan
11
¿Qué sucede si quiero que cante cada comando a través de un sintetizador de voz similar a un vocaloide al hacer eco, para poder escuchar lo que está haciendo a distancia y también disfrutar de la música? Quizás en una voz diferente para entradas y salidas.
ADJenks
(El ABS tiene una larga historia de no responder a las solicitudes de que corrijan ejemplos de malas prácticas, hasta el punto de llevar a miembros de la comunidad de larga data a crear recursos competitivos; movió los enlaces a la wiki de los piratas informáticos: la wiki de Wooledge o la manual de bash oficial también sería mejores recursos).
Charles Duffy
317

set -x te dará lo que quieres

Aquí hay un ejemplo de script de shell para demostrar:

#!/bin/bash
set -x #echo on

ls $PWD

Esto expande todas las variables e imprime los comandos completos antes de la salida del comando.

Salida:

+ ls /home/user/
file1.txt file2.txt
radman
fuente
21
Usar la palabra "detallado" de esa manera no logra nada. Puede hacer set -o verboseo set -v(solo "detallado") o set -o xtraceo set -x(solo "xtrace") o set -xv(ambos) o set -o xtrace -o verbose(ambos).
Pausado hasta nuevo aviso.
esto funciona bien, pero tenga en cuenta que el "detallado" sobrescribe $ 1
JasonS
90

Yo uso una función para hacer eco y ejecutar el comando:

#!/bin/bash
# Function to display commands
exe() { echo "\$ $@" ; "$@" ; }

exe echo hello world

Que salidas

$ echo hello world
hello world

Para tuberías de comandos más complicadas, etc., puede usar eval:

#!/bin/bash
# Function to display commands
exe() { echo "\$ ${@/eval/}" ; "$@" ; }

exe eval "echo 'Hello, World!' | cut -d ' ' -f1"

Que salidas

$  echo 'Hello, World!' | cut -d ' ' -f1
Hello
Soth
fuente
No hay muchos votos para esta respuesta. ¿Hay alguna razón por la que es una mala idea? Trabajado para mí, y parece ser exactamente lo que estoy buscando ...
fru1tbat
1
Esta es la mejor respuesta si no desea que se impriman todos los comandos. Evita la ++ set +xsalida cuando se apaga, además de verse más limpia. Sin embargo, solo para una o dos afirmaciones, la respuesta de Bhassel usando un subshell es la más conveniente.
Brent Faust
¡Esto es lo que estoy buscando! No set +x, afecta a todos los comandos, ¡lo cual es demasiado!
Hlung
11
Una desventaja importante de esto es que el producto pierde la información de cotización. No se puede diferenciar entre cp "foo bar" bazy cp foo "bar baz", por ejemplo. Por lo tanto, es bueno para mostrar información de progreso a un usuario; menos para depurar resultados o grabar comandos reproducibles. Diferentes casos de uso. En zsh, puede conservar las citas con el :qmodificador:exe() { echo '$' "${@:q}" ; "$@" ; }
Andrew Janke
2
No me gusta esta respuesta. Hay muchos casos extremos donde lo que ves no es lo que obtienes (especialmente con espacios en blanco, comillas, caracteres escapados, sustituciones de variables / expresiones, etc.), así que no pegues ciegamente el comando echoed en un terminal y asume que se ejecutará de la misma manera Además, la segunda técnica es solo un truco y eliminará otras instancias de la palabra evalde su comando. ¡Así que no esperes que funcione correctamente exe eval "echo 'eval world'"!
mwfearnley
88

También puede alternar esto para seleccionar líneas en su secuencia de comandos envolviéndolas set -xy set +x, por ejemplo,

#!/bin/bash
...
if [[ ! -e $OUT_FILE ]];
then
   echo "grabbing $URL"
   set -x
   curl --fail --noproxy $SERV -s -S $URL -o $OUT_FILE
   set +x
fi
shuckc
fuente
54

La respuesta de shuckc para hacer eco de las líneas de selección tiene algunas desventajas: terminas haciendo que se repita también el siguiente set +xcomando y pierdes la capacidad de probar el código de salida, $?ya que se sobrescribe con el set +x.

Otra opción es ejecutar el comando en una subshell:

echo "getting URL..."
( set -x ; curl -s --fail $URL -o $OUTFILE )

if [ $? -eq 0 ] ; then
    echo "curl failed"
    exit 1
fi

que le dará salida como:

getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed

Sin embargo, esto conlleva la sobrecarga de crear una nueva subshell para el comando.

Bhassel
fuente
77
Buena manera de evitar la ++ set +xsalida.
Brent Faust
3
Aún mejor: reemplazar if [ $? -eq 0 ]con if (set -x; COMMAND).
Amedee Van Gasse
35

Otra opción es poner "-x" en la parte superior de su script en lugar de en la línea de comando:

$ cat ./server
#!/bin/bash -x
ssh user@server

$ ./server
+ ssh user@server
user@server's password: ^C
$
nooj
fuente
Tenga en cuenta que esto no parece funcionar exactamente igual entre ./myScripty bash myScript. Todavía es algo bueno señalar, gracias.
altendky
27

De acuerdo con la Guía Bash de TLDP para principiantes: Capítulo 2. Escritura y depuración de scripts :

2.3.1. Depuración de todo el script

$ bash -x script1.sh

...

Ahora hay un depurador completo para Bash, disponible en SourceForge . Estas funciones de depuración están disponibles en la mayoría de las versiones modernas de Bash, a partir de 3.x.

2.3.2. Depuración en parte (s) del script

set -x            # Activate debugging from here
w
set +x            # Stop debugging from here

...

Tabla 2-1. Descripción general de las opciones de depuración establecidas

    Short  | Long notation | Result
    -------+---------------+--------------------------------------------------------------
    set -f | set -o noglob | Disable file name generation using metacharacters (globbing).
    set -v | set -o verbose| Prints shell input lines as they are read.
    set -x | set -o xtrace | Print command traces before executing command.

...

Alternativamente, estos modos se pueden especificar en el script en sí mismo, agregando las opciones deseadas a la declaración de shell de la primera línea. Las opciones se pueden combinar, como suele ser el caso con los comandos UNIX:

#!/bin/bash -xv
Afriza N. Arief
fuente
18

Escriba "bash -x" en la línea de comando antes del nombre del script Bash. Por ejemplo, para ejecutar foo.sh, escriba:

bash -x foo.sh
Alan
fuente
11

Puede ejecutar un script Bash en modo de depuración con la -xopción .

Esto hará eco de todos los comandos.

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

También puede guardar la opción -x en el script . Simplemente especifique la -xopción en el shebang.

######## example_script.sh ###################
#!/bin/bash -x

cd /home/user
mv text.txt mytext.txt

##############################################

./example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt
RenRen
fuente
2
También bash -vxhará lo mismo pero sin la interpolación de variables
loa_in_
4

Para zsh, echo

 setopt VERBOSE

Y para depurar,

 setopt XTRACE
zzapper
fuente
2

Para cshy tcsh, puede set verboseo set echo(o incluso puede configurar ambos, pero puede resultar en alguna duplicación la mayor parte del tiempo).

La verboseopción imprime más o menos la expresión de shell exacta que escribe.

La echoopción es más indicativa de lo que se ejecutará durante el desove.


http://www.tcsh.org/tcsh.html/Special_shell_variables.html#verbose

http://www.tcsh.org/tcsh.html/Special_shell_variables.html#echo


Special shell variables

verbose If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.

echo If set, each command with its arguments is echoed just before it is executed. For non-builtin commands all expansions occur before echoing. Builtin commands are echoed before command and filename substitution, because these substitutions are then done selectively. Set by the -x command line option.

cnst
fuente
1
$ cat exampleScript.sh
#!/bin/bash
name="karthik";
echo $name;

bash -x exampleScript.sh

La salida es la siguiente:

ingrese la descripción de la imagen aquí

Karthik Arun
fuente
¿Cuáles son las definiciones de color para su terminal (RGB, numérico)?
Peter Mortensen el
1

Para permitir que los comandos compuestos se repitan, utilizo evalmás la exefunción de Soth para hacer eco y ejecutar el comando. Esto es útil para los comandos canalizados que de otro modo solo mostrarían ninguno o solo la parte inicial del comando canalizado.

Sin eval:

exe() { echo "\$ $@" ; "$@" ; }
exe ls -F | grep *.txt

Salidas:

$
file.txt

Con eval:

exe() { echo "\$ $@" ; "$@" ; }
exe eval 'ls -F | grep *.txt'

Que salidas

$ exe eval 'ls -F | grep *.txt'
file.txt
Paul Havens
fuente