Como verificar qual linha de um script bash está sendo executada

15

Existe uma maneira de verificar qual número de linha de um bashscript está sendo executado "agora"?

Usando bash -x script.shparece promissor; no entanto, preciso obter o número da linha atual.

user224371
fonte

Respostas:

20

Combine xtracecom PS4dentro do script:

$ 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

ou no shell pai :

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

Sim, há um jeito.
Há uma matriz de números de linha em que uma função foi chamada.

Defina esta função:

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

E ligue fpara qualquer linha que você deseja o número da linha, por exemplo:

#!/bin/bash


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

f

echo next1
f

echo next2
f

echo next 3
f

Irá imprimir:

6
next 1
9
next 2
12
next 3
15

Pode ser expandido para mostrar a trilha de funções chamada:

#!/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

Qual será impresso:

$ ./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

Observe que acima da echo "$LINENO"saída é sempre a mesma (7 neste caso).

sorontar
fonte
7

Aqui está uma solução que empresta partes das respostas de 10b0 e de DopeGhoti (e, em menor grau, das respostas de sorontar ). Como essas respostas, a minha usa $LINENOpara descobrir o número da linha; ao contrário deles, eu uso trappara acionar os relatórios. O trapcomando do bash é descrito em bash (1) :

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

    O comando arg deve ser lido e executado quando o shell receber sinal (es) sigspec . … ⁠ ︙
    … Se um sigspec é DEBUG , o comando arg é executado antes de todo comando simples , forcomando, casecomando, selectcomando, todo forcomando aritmético e antes do primeiro comando ser executado em uma função de shell…

Então 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))
$

executa o printf "%3d: " "$LINENO"comando antes de cada comando no script e produz esta saída:

$ ./myscript
  3: Qua, 5 de abr de 2017 10:16:17
  4: 5: Quarta-feira, 05 de abril de 2017 10:16:47
  7: 8: Qua, 05 de abril de 2017 10:16:58
 10: total 4
-rwxr-xr-x 1 myusername mygroup 221 5 de abril às 10:01 myscript
-rwxr-xr-x 1 myusername mygroup 252 5 de abril às 10:01 myscript2
-rw-r - r-- 1 myusername mygroup 132 5 de abril às 09:59 myscript2.log
-rw-r - r-- 1 myusername mygroup   45 abr 5 08:34 other_file
 11: 13: myscript
 14: -rwxr-xr-x 1 myusername mygroup 221 5 de abril às 10:01 myscript
 11: 13: myscript2
 14: -rwxr-xr-x 1 myusername mygroup 252 5 de abril às 10:01 myscript2
 11: 13: myscript2.log
 14: -rw-r - r-- 1 myusername mygroup 132 Abr 5 09:59 myscript2.log
 11: 13: other_file
 14: -rw-r - r-- 1 myusername mygroup   45 abr 5 08:34 other_file
 17: 17: 19: i = 0
 19: Qua, 05 de abril de 2017 10:16:59
 17: 17: 19: i = 1
 19: Qua, 05 de abril de 2017 10:16:59
 17: 17: 19: i = 2
 19: Qua, 05 de abril de 2017 10:16:59
 17: 17: 22: 42
$

Notas:

  • Como a resposta de l0b0 , isso é minimamente invasivo - basta adicionar a linha 2.
  • Diferentemente da resposta de l0b0 , isso não exibe os comandos em si - mas você não pediu para fazer isso.
  • O segundo sleep, que abrange as linhas de script 6 e 7, é relatado como linha 7.
  • A linha 11 ( for f in *) é relatada uma vez antes de cada iteração desse forloop.
  • echo "$f"e ls -ld "$f"são relatados corretamente em suas respectivas linhas (13 e 14).
  • A linha 17 ( for ((i=0; i<3; i++))) é relatada duas vezes antes de cada iteração desse forloop e duas vezes mais após a última iteração.
  • Ao contrário set -x, LINENOe PS4 (que são especificados pelo padrão POSIX), o DEBUG trapé uma extensão do bash e não funcionará em todas as conchas.
  • O DEBUG trappode executar qualquer comando (s) e não está restrito à gravação na saída padrão do erro ou no erro padrão.

A pergunta diz: "verifique qual número de linha de um script bash está sendo executado" agora "" sem especificar uma interface de usuário. Outra abordagem é gravar continuamente o número da linha atual em um arquivo de log:

$ diff myscript myscript2
2c2
<trap 'printf "% 3d:" "$ LINENO"' DEBUG
---
> exec 6> myscript2.log && trap 'printf "% 3d \ n" "$ LINENO"> & 6' DEBUG
$ ./myscript2
Quarta-feira, 5 de abril de 2017 10:23:50
Quarta-feira, 5 de abril de 2017 10:24:20
Quarta-feira, 5 de abril de 2017 10:24:31
4 total
-rwxr-xr-x 1 myusername mygroup 221 5 de abril às 10:01 myscript
-rwxr-xr-x 1 myusername mygroup 252 5 de abril às 10:01 myscript2
-rw-r - r-- 1 myusername mygroup   24 de abril 5 10:23 myscript2.log
-rw-r - r-- 1 myusername mygroup   45 abr 5 08:34 other_file
myscript
-rwxr-xr-x 1 myusername mygroup 221 5 de abril às 10:01 myscript
myscript2
-rwxr-xr-x 1 myusername mygroup 252 5 de abril às 10:01 myscript2
myscript2.log
-rw-r - r-- 1 myusername mygroup   60 5 de abr 10:23 myscript2.log
other_file
-rw-r - r-- 1 myusername mygroup   45 abr 5 08:34 other_file
i = 0
Quarta-feira, 5 de abril de 2017 10:24:31
i = 1
Quarta-feira, 5 de abril de 2017 10:24:31
i = 2
Quarta-feira, 5 de abril de 2017 10:24:31
42.
$

Podemos monitorar a execução desse script, monitorando o conteúdo do myscript2.logarquivo de outro terminal. Por exemplo, durante o segundo sleep,

$ tail myscript2.log
  3
  4
  5
  7
G-Man Diz 'Reinstate Monica'
fonte
6

Você pode echo $LINENOem um script e deve exibir qualquer linha em que esse comando esteja.

#!/bin/bash
echo $LINENO

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

Adicione esse "-x" no início do seu script. Então, toda vez que você executar o script, ele ecoará na linha que seu script está executando. como uma árvore de execução do seu script.

Pavan Shah
fonte
4
O OP já descartou essa sugestão como insatisfatória.
G-Man diz 'Reinstate Monica'