Jak sprawdzić, która linia skryptu bash jest wykonywana


15

Czy istnieje sposób, aby sprawdzić, która linia numer o bashskrypt jest wykonywany „teraz”?

Korzystanie bash -x script.shwygląda obiecująco; muszę jednak uzyskać bieżący numer linii.

Odpowiedzi:


20

Połącz xtracez PS4wewnątrz skryptu:

$ 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

lub w powłoce nadrzędnej :

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

10

Tak, jest sposób.
Istnieje tablica numerów linii, w których wywołano funkcję.

Zdefiniuj tę funkcję:

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

I dzwoń fna dowolną linię, na którą chcesz uzyskać numer linii, na przykład:

#!/bin/bash


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

f

echo next1
f

echo next2
f

echo next 3
f

Wydrukuje:

6
next 1
9
next 2
12
next 3
15

Można go rozszerzyć, aby pokazać szereg funkcji o nazwie:

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

Który wydrukuje:

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

Zauważ, że powyżej echo "$LINENO"wyjście jest zawsze takie samo (w tym przypadku 7).


7

Oto rozwiązanie, które pożycza części odpowiedzi L0b0 i DopeGhoti (oraz, w mniejszym stopniu, odpowiedzi Sorontara ). Podobnie jak te odpowiedzi, moje używa $LINENOdo odkrycia numeru linii; w przeciwieństwie do nich, używam trapdo uruchamiania raportowania. trapPolecenie bash opisano w bash (1) :

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

    Polecenie arg należy odczytać i wykonać, gdy powłoka odbierze sygnał (-y) sigspec . … ⁠ ︙
    … Jeśli sigspec to DEBUG , polecenie arg jest wykonywane przed każdą prostą komendą , forkomendą, casekomendą, selectkomendą, każdą forkomendą arytmetyczną i przed wykonaniem pierwszej komendy w funkcji powłoki…

Więc ten skrypt:

$ 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))
$

uruchamia printf "%3d: " "$LINENO"polecenie przed każdym poleceniem w skrypcie i generuje następujące dane wyjściowe:

$ ./myscript
  3: śr., 05 kwietnia 2017 10:16:17
  4: 5: śr., 05 kwietnia 2017 10:16:47
  7: 8: śr., 05 kwietnia 2017 10:16:58
 10: łącznie 4
-rwxr-xr-x 1 moja nazwa użytkownika moja grupa 221 5 kwietnia 10:01 mój skrypt
-rwxr-xr-x 1 moja nazwa użytkownika moja grupa 252 5 kwietnia 10:01 myscript2
-rw-r - r-- 1 moja nazwa użytkownika moja grupa 132 kwi 5 09:59 myscript2.log
-rw-r - r-- 1 moja nazwa użytkownika moja grupa   45 kwietnia 5 08:34 inny_plik
 11: 13: myscript
 14: -rwxr-xr-x 1 moja nazwa użytkownika moja grupa 221 5 kwietnia 10:01 myscript
 11: 13: myscript2
 14: -rwxr-xr-x 1 moja nazwa użytkownika moja grupa 252 5 kwietnia 10:01 myscript2
 11: 13: myscript2.log
 14: -rw-r - r-- 1 moja nazwa użytkownika moja grupa 132 kwi 5 09:59 myscript2.log
 11: 13: inny_plik
 14: -rw-r - r-- 1 moja nazwa użytkownika moja grupa   45 kwietnia 5 08:34 inny_plik
 17: 17: 19: i = 0
 19: śr., 05 kwietnia 2017 10:16:59
 17: 17: 19: i = 1
 19: śr., 05 kwietnia 2017 10:16:59
 17: 17: 19: i = 2
 19: śr., 05 kwietnia 2017 10:16:59
 17: 17: 22: 42
$

Uwagi:

  • Podobnie jak odpowiedź l0b0 , jest to minimalnie inwazyjne - wystarczy dodać wiersz 2.
  • W przeciwieństwie do odpowiedzi l0b0 , same polecenia nie są wyświetlane - ale nie poprosiłeś o to, aby to zrobić.
  • Drugi sleep, który obejmuje wiersze 6 i 7 skryptu, jest zgłaszany jako wiersz 7.
  • Wiersz 11 ( for f in *) jest zgłaszany raz przed każdą iteracją tej forpętli.
  • echo "$f"i ls -ld "$f"są poprawnie zgłaszane na odpowiednich liniach (13 i 14).
  • Wiersz 17 ( for ((i=0; i<3; i++))) jest zgłaszany dwa razy przed każdą iteracją tej forpętli i jeszcze dwa razy po ostatniej iteracji.
  • W przeciwieństwie set -x, LINENOi PS4 (które są określone przez standard POSIX), DEBUG trapjest rozszerzeniem bash i nie będzie działać we wszystkich muszli.
  • DEBUG trapmoże uruchamiać dowolne polecenia i nie ogranicza się do zapisywania na standardowe wyjście skryptu lub standardowy błąd.

Pytanie brzmi: „sprawdź, który numer wiersza skryptu bash jest wykonywany„ teraz ”” bez określania interfejsu użytkownika. Innym podejściem jest ciągłe zapisywanie bieżącego numeru wiersza w pliku dziennika:

$ diff myscript myscript2
2c2
<pułapka 'printf "% 3d:" "$ LINENO"' DEBUG
---
> exec 6> myscript2.log && trap 'printf "% 3d \ n" "$ LINENO"> & 6' DEBUG
$ ./myscript2
Śr., 05 kwietnia 2017 10:23:50
Śr., 05 kwietnia 2017 10:24:20
Śr., 05 kwietnia 2017 10:24:31
razem 4
-rwxr-xr-x 1 moja nazwa użytkownika moja grupa 221 5 kwietnia 10:01 mój skrypt
-rwxr-xr-x 1 moja nazwa użytkownika moja grupa 252 5 kwietnia 10:01 myscript2
-rw-r - r-- 1 moja nazwa użytkownika moja grupa   24 kwietnia 5 10:23 myscript2.log
-rw-r - r-- 1 moja nazwa użytkownika moja grupa   45 kwietnia 5 08:34 inny_plik
mój skrypt
-rwxr-xr-x 1 moja nazwa użytkownika moja grupa 221 5 kwietnia 10:01 mój skrypt
myscript2
-rwxr-xr-x 1 moja nazwa użytkownika moja grupa 252 5 kwietnia 10:01 myscript2
myscript2.log
-rw-r - r-- 1 moja nazwa użytkownika moja grupa   60 kwietnia 5 10:23 myscript2.log
inny_plik
-rw-r - r-- 1 moja nazwa użytkownika moja grupa   45 kwietnia 5 08:34 inny_plik
i = 0
Śr., 05 kwietnia 2017 10:24:31
i = 1
Śr., 05 kwietnia 2017 10:24:31
i = 2
Śr., 05 kwietnia 2017 10:24:31
42
$

Możemy monitorować wykonanie tego skryptu, monitorując zawartość myscript2.logpliku z innego terminala. Na przykład, podczas drugiego sleep,

$ tail myscript2.log
  3
  4
  5
  7

6

Możesz echo $LINENOw skrypcie, który powinien wypisać dowolny wiersz, w którym znajduje się polecenie.

#!/bin/bash
echo $LINENO

$ ./foo.sh
2

-1
#!/bin/bash -x

Dodaj „-x” na początku skryptu. Następnie za każdym razem, gdy wykonujesz skrypt, będzie on odzwierciedlał linię wykonywaną przez skrypt. jak drzewo wykonania skryptu.


4
PO już odrzucił tę sugestię jako niezadowalającą.
G-Man mówi „Przywróć Monikę”
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.