Cómo verificar qué línea de un script bash se está ejecutando

15

¿Hay alguna manera de verificar qué número de línea de un bashscript se está ejecutando "en este momento"?

Usar bash -x script.shlooks prometedores; Sin embargo, necesito obtener el número de línea actual.

usuario224371
fuente

Respuestas:

20

Combinar xtracecon PS4dentro del guión:

$ cat test.sh 
#!/usr/bin/env bash
set -x
PS4='+${LINENO}: '

sleep 1m
sleep 1d
$ timeout 5 ./test.sh
+3: PS4='+${LINENO}: '
+5: sleep 1m

o en el shell principal :

$ cat test.sh 
sleep 1m
sleep 1d
$ export PS4='+${LINENO}: '
$ timeout 5 bash -x ./test.sh
+1: sleep 1m
l0b0
fuente
10

Sí, hay una manera.
Hay una serie de números de línea donde se ha llamado a una función.

Defina esta función:

f(){ echo "${BASH_LINENO[-2]}"; }

Y llame fa cualquier línea que desee el número de línea, por ejemplo:

#!/bin/bash


f(){ echo "${BASH_LINENO[-2]}"; }

f

echo next1
f

echo next2
f

echo next 3
f

Imprimirá:

6
next 1
9
next 2
12
next 3
15

Se podría ampliar para mostrar el rastro de funciones llamadas:

#!/bin/bash

f(){
    for ((i=${#BASH_LINENO[@]}-1;i>=0;i--)); do
    printf '<%s:%s> ' "${FUNCNAME[i]}" "${BASH_LINENO[i]}";
    done
    echo "$LINENO"
 }

SomeOtherFunction(){ echo -n "test the line numbering:  "; f; }

f

echo next 1
echo -n "    This line numbering:  "; f
SomeOtherFunction

echo next 2
echo -n "    This line numbering:  "; f
SomeOtherFunction

echo next 3
echo -n "    This line numbering:  "; f

Que imprimirá:

$ ./script
<main:0> <f:12> 7
next 1
    This line numbering:  <main:0> <f:15> 7
test the line numbering:  <main:0> <SomeOtherFunction:16> <f:10> 7
next 2
    This line numbering:  <main:0> <f:19> 7
test the line numbering:  <main:0> <SomeOtherFunction:20> <f:10> 7
next 3
    This line numbering:  <main:0> <f:23> 7

Tenga en cuenta que por encima de la echo "$LINENO"salida es siempre la misma (7 en este caso).

sorontar
fuente
7

Aquí hay una solución que toma prestadas partes de las respuestas de l0b0 y DopeGhoti (y, en menor medida, las de sorontar ). Al igual que esas respuestas, la mía usa $LINENOpara descubrir el número de línea; a diferencia de ellos, uso trappara activar los informes. El trapcomando de bash se describe en bash (1) :

trap [-lp] [[arg] sigspec ...]

    El comando arg debe leerse y ejecutarse cuando el shell recibe señal (es) sigspec . ... ⁠ ︙
    ... Si un sigspec es DEBUG , el comando arg se ejecuta antes de cada comando simple , forcomando, casecomando, selectcomando, cada forcomando aritmético , y antes de que el primer comando se ejecute en una función de shell ...

Entonces este script:

$ cat -n myscript
     1  #!/bin/bash
     2  trap 'printf "%3d: " "$LINENO"' DEBUG
     3  date
     4  sleep 30
     5  date
     6  sleep \
     7        11
     8  date
     9
    10  ls -l
    11  for f in *
    12  do
    13          echo "$f"  &&
    14                         ls -ld "$f"
    15  done
    16
    17  for ((i=0; i<3; i++))
    18  do
    19          echo "i = $i"; date
    20  done
    21
    22  echo $((5+25+12))
$

ejecuta el printf "%3d: " "$LINENO"comando antes de cada comando en el script y produce esta salida:

$ ./myscript
  3: Mié, 05 de abril de 2017 10:16:17 a.m.
  4: 5: mié, 05 de abril de 2017 10:16:47 a.m.
  7: 8: mié, 05 de abril de 2017 10:16:58 a.m.
 10: total 4
-rwxr-xr-x 1 myusername mygroup 221 5 de abril 10:01 myscript
-rwxr-xr-x 1 myusername mygroup 252 5 de abril 10:01 myscript2
-rw-r - r-- 1 myusername mygroup 132 5 de abril 09:59 myscript2.log
-rw-r - r-- 1 myusername mygroup   45 5 de abril 08:34 otro_archivo
 11: 13: MyScript
 14: -rwxr-xr-x 1 myusername mygroup 221 5 de abril 10:01 myscript
 11: 13: myscript2
 14: -rwxr-xr-x 1 myusername mygroup 252 5 de abril 10:01 myscript2
 11: 13: myscript2.log
 14: -rw-r - r-- 1 myusername mygroup 132 5 de abril 09:59 myscript2.log
 11: 13: otro_archivo
 14: -rw-r - r-- 1 myusername mygroup   45 5 de abril 08:34 otro_archivo
 17: 17: 19: i = 0
 19: mié, 05 de abril de 2017 10:16:59 a.m.
 17: 17: 19: i = 1
 19: mié, 05 de abril de 2017 10:16:59 a.m.
 17: 17: 19: i = 2
 19: mié, 05 de abril de 2017 10:16:59 a.m.
 17: 17: 22: 42
PS

Notas:

  • Al igual que la respuesta de l0b0 , esto es mínimamente invasivo: solo agregue la línea 2.
  • A diferencia de la respuesta de l0b0 , esto no muestra los comandos en sí, pero usted no solicitó que lo hiciera.
  • El segundo sleep, que abarca las líneas de guión 6 y 7, se informa como la línea 7.
  • La línea 11 ( for f in *) se informa una vez antes de cada iteración de ese forciclo.
  • echo "$f"y ls -ld "$f"se informan correctamente en sus respectivas líneas (13 y 14).
  • La línea 17 ( for ((i=0; i<3; i++))) se informa dos veces antes de cada iteración de ese forciclo, y dos veces más después de la última iteración.
  • A diferencia de set -x, LINENOy PS4 (que se especifican en el estándar POSIX), DEBUG trapes una extensión bash y no funcionará en todos los shells.
  • El DEPURACIÓN trappuede ejecutar cualquier comando (s), y no está restringido a escribir en la salida estándar del script o error estándar.

La pregunta dice: «compruebe qué número de línea de un script bash se está ejecutando" en este momento "» sin especificar una interfaz de usuario. Otro enfoque es escribir continuamente el número de línea actual en un archivo de registro:

$ diff myscript myscript2
2c2
<trap 'printf "% 3d:" "$ LINENO"' DEBUG
---
> exec 6> myscript2.log && trap 'printf "% 3d \ n" "$ LINENO"> & 6' DEPURACIÓN
$ ./myscript2
Mié, 05 de abril de 2017 10:23:50 a.m.
Mié, 05 de abril de 2017 10:24:20 a.m.
Mié, 05 de abril de 2017 10:24:31 a.m.
total 4
-rwxr-xr-x 1 myusername mygroup 221 5 de abril 10:01 myscript
-rwxr-xr-x 1 myusername mygroup 252 5 de abril 10:01 myscript2
-rw-r - r-- 1 myusername mygroup   24 abr 5 10:23 myscript2.log
-rw-r - r-- 1 myusername mygroup   45 5 de abril 08:34 otro_archivo
MyScript
-rwxr-xr-x 1 myusername mygroup 221 5 de abril 10:01 myscript
myscript2
-rwxr-xr-x 1 myusername mygroup 252 5 de abril 10:01 myscript2
myscript2.log
-rw-r - r-- 1 myusername mygroup   60 5 de abril 10:23 myscript2.log
otro_archivo
-rw-r - r-- 1 myusername mygroup   45 5 de abril 08:34 otro_archivo
i = 0
Mié, 05 de abril de 2017 10:24:31 a.m.
i = 1
Mié, 05 de abril de 2017 10:24:31 a.m.
i = 2
Mié, 05 de abril de 2017 10:24:31 a.m.
42
PS

Podemos monitorear la ejecución de este script al monitorear el contenido del myscript2.logarchivo desde otro terminal. Por ejemplo, durante el segundo sleep,

$ tail myscript2.log
  3
  4
  5
  7
G-Man dice 'restablecer a Mónica'
fuente
6

Puede echo $LINENOhacerlo en un script y debería generar cualquier línea en la que se encuentre ese comando.

#!/bin/bash
echo $LINENO

$ ./foo.sh
2
DopeGhoti
fuente
-1
#!/bin/bash -x

Agregue ese "-x" al comienzo de su secuencia de comandos. Luego, cada vez que ejecute el script, se hará eco de la línea que ejecuta su script. como un árbol de ejecución de tu script.

Pavan Shah
fuente
44
El OP ya ha descartado esta sugerencia por ser insatisfactoria.
G-Man dice 'reinstalar a Mónica' el