Jak debugować skrypt bash? [Zamknięte]


159

Czy istnieje sposób na debugowanie skryptu bash? Np. Coś, co drukuje rodzaj dziennika wykonywania, jak „linia wywołująca 1”, „linia wywołująca 2” itd.


2
Tutaj pojawia się podobne pytanie: serverfault.com/questions/16204/…
Wstrzymano do odwołania.

Odpowiedzi:


195
sh -x script [arg1 ...]
bash -x script [arg1 ...]

Dają ci ślad tego, co jest wykonywane. (Zobacz także „Wyjaśnienie” u dołu odpowiedzi).

Czasami trzeba kontrolować debugowanie w skrypcie. W takim razie, jak przypomniał mi Cheeto , możesz użyć:

set -x

To włącza debugowanie. Następnie możesz go ponownie wyłączyć za pomocą:

set +x

(Możesz sprawdzić bieżący stan śledzenia, analizując $-bieżące flagi dla x).

Ponadto powłoki generalnie udostępniają opcje „ -n” dla „braku wykonywania” i „ -v” dla trybu „gadatliwego”; możesz użyć ich w połączeniu, aby sprawdzić, czy powłoka uważa, że ​​może wykonać twój skrypt - czasami przydatne, jeśli gdzieś masz niezrównoważony cytat.


Istnieje twierdzenie, że -xopcja „ ” w Bash różni się od innych powłok (patrz komentarze). Instrukcja Bash mówi:

  • -x

    Wydrukuj ślad prostych poleceń, forpoleceń, casepoleceń, selectpoleceń i forpoleceń arytmetycznych oraz ich argumentów lub powiązanych list słów po ich rozwinięciu i przed wykonaniem. Wartość PS4zmiennej jest interpretowana, a wynikowa wartość jest wypisywana przed poleceniem i jego rozwiniętymi argumentami.

To wcale nie wydaje się wskazywać na inne zachowanie. Nie widzę żadnych innych odnośnych odniesień do „ -x” w instrukcji. Nie opisuje różnic w kolejności startowej.

Wyjaśnienie : W systemach takich jak typowy Linux, gdzie „ /bin/sh” jest dowiązaniem symbolicznym do „ /bin/bash” (lub gdziekolwiek zostanie znaleziony plik wykonywalny Bash), dwie linie poleceń osiągają równoważny efekt uruchamiania skryptu z włączonym śledzeniem wykonania. W innych systemach (na przykład Solaris i niektóre bardziej nowoczesne warianty Linuksa) /bin/shnie jest Bash, a dwie linie poleceń dałyby (nieco) różne wyniki. Przede wszystkim „ /bin/sh” byłby zdezorientowany przez konstrukcje w Bash, których w ogóle nie rozpoznaje. (W Solarisie /bin/shjest to powłoka Bourne'a; we współczesnym Linuksie jest to czasami Dash - mniejsza, bardziej ściśle zgodna tylko z POSIX-owa powłoka). Po wywołaniu z taką nazwą, linia „shebang” ( #!/bin/bash„vs '#!/bin/sh

Podręcznik Bash zawiera sekcję o trybie Bash POSIX, który w przeciwieństwie do długotrwałej, ale błędnej wersji tej odpowiedzi (zobacz również komentarze poniżej), opisuje szczegółowo różnicę między 'Bash wywołany jako sh' a 'Bash wywołany jako' bash”.

Podczas debugowania (Bash) skryptu powłoki rozsądne i rozsądne będzie - nawet konieczne - użycie powłoki wymienionej w linii shebang z -xopcją. W przeciwnym razie możesz (będzie?) Uzyskać inne zachowanie podczas debugowania niż podczas uruchamiania skryptu.


1
Określił bashscenariusz. Uruchomienie skryptu bash w programie sh -xsprawi, że będzie się on zachowywał zupełnie inaczej! Zaktualizuj swoją odpowiedź.
lhunath

1
@lhunath: W jaki sposób „sh -x” (lub „bash -x”) powoduje, że skrypt zachowuje się zupełnie inaczej? Oczywiście przekazuje informacje o śledzeniu na stderr; to jest dane (choć nie zostało wspomniane w mojej odpowiedzi). Ale co jeszcze? Używam „bash” jako „sh” na Linuksie i MacOS X i nie zauważyłem poważnego problemu.
Jonathan Leffler

6
Istnieją różnice w uruchamianiu i w czasie wykonywania. Są w pełni udokumentowane w dystrybucji Bash.
TheBonsai

4
Oto link do dokumentu bash: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'Jeśli Bash jest wywoływany z nazwą sh, próbuje naśladować zachowanie startowe historycznych wersji sh as jak najściślej, przy jednoczesnym zachowaniu zgodności ze standardem posix ”
thethinman

6
I użyj podpowiedzi PS4, aby podać bardziej przydatne informacje, takie jak:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani

28

Użyłem następujących metod do debugowania mojego skryptu.

set -epowoduje natychmiastowe zatrzymanie skryptu, jeśli jakikolwiek program zewnętrzny zwróci niezerowy kod zakończenia. Jest to przydatne, jeśli twój skrypt próbuje obsłużyć wszystkie przypadki błędów i gdzie niepowodzenie powinno zostać złapane.

set -x został wspomniany powyżej iz pewnością jest najbardziej użyteczną ze wszystkich metod debugowania.

set -n może być również przydatne, jeśli chcesz sprawdzić skrypt pod kątem błędów składniowych.

stracejest również przydatne, aby zobaczyć, co się dzieje. Szczególnie przydatne, jeśli sam nie napisałeś scenariusza.


1
Śledzenie skryptu (tj. Umieszczanie powłoki w powłoce wykonującej skrypt) jest dziwną metodą debugowania powłoki (ale może działać w przypadku ograniczonego zestawu problemów).
TheBonsai

1
Przyznaję, że jest to dziwne i bardzo rozwlekłe, ale jeśli ograniczysz wyjście strace do kilku wywołań systemowych, stanie się to przydatne.

1
Zauważ, że strace -fjest to potrzebne, jeśli chcesz również znaleźć błędy w procesach uruchomionych przez skrypt. (co sprawia, że ​​jest wielokrotnie bardziej rozwlekły, ale nadal przydatny, jeśli ograniczysz go do wywołań systemowych, które Cię interesują).
Random832

set -ejest ... kontrowersyjny .
Charles Duffy

12

Ta odpowiedź jest poprawna i przydatna: https://stackoverflow.com/a/951352

Jednak uważam, że „standardowe” metody debugowania skryptów są nieefektywne, nieintuicyjne i trudne w użyciu. Dla osób przyzwyczajonych do wyrafinowanych debuggerów GUI, które umieszczają wszystko na wyciągnięcie ręki i sprawiają, że praca jest szybka w przypadku łatwych problemów (i możliwych w przypadku trudnych problemów), te rozwiązania nie są zbyt satysfakcjonujące.

Używam kombinacji DDD i bashdb. Pierwsza wykonuje drugą, a druga wykonuje skrypt. Zapewnia to interfejs użytkownika z wieloma oknami z możliwością przechodzenia przez kod w kontekście i przeglądania zmiennych, stosu itp., Bez ciągłego wysiłku umysłowego w celu utrzymania kontekstu w głowie lub ponownego wyświetlania źródła.

Wskazówki, jak to zrobić, znajdziesz tutaj: http://ubuntuforums.org/showthread.php?t=660223


Właśnie odkryłem ddd dzięki twojej odpowiedzi. W Ubuntu 12.04.3 (64-bitowy) wersja apt-sources nie działa. Musiałem skompilować i zainstalować ze źródła, aby rozpocząć debugowanie skryptu bash. Instrukcje tutaj - askubuntu.com/questions/156906/ ... pomogły.
chronodekar

Tak, to jest problem. Rozwiązałem to jakiś czas temu za pomocą skryptów - `` dddbash '' instaluje / buduje DDD, usuwa starą wersję, jeśli jest nieprawidłowa, instaluje bashdb itp. (Odpowiedź została zmieniona z tymi informacjami)
Stabledog


10

Znalazłem narzędzie Shellcheck i może być dla niektórych osób interesujące https://github.com/koalaman/shellcheck

Mały przykład:

$ cat test.sh 
ARRAY=("hello there" world)

for x in $ARRAY; do
  echo $x
done

$ shellcheck test.sh 

In test.sh line 3:
for x in $ARRAY; do
         ^-- SC2128: Expanding an array without an index only gives the first element.

napraw błąd, najpierw spróbuj ...

$ cat test.sh       
ARRAY=("hello there" world)

for x in ${ARRAY[@]}; do
  echo $x
done

$ shellcheck test.sh

In test.sh line 3:
for x in ${ARRAY[@]}; do
         ^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces.

Spróbujmy ponownie...

$ cat test.sh 
ARRAY=("hello there" world)

for x in "${ARRAY[@]}"; do
  echo $x
done

$ shellcheck test.sh

Znajdź teraz!

To tylko mały przykład.


1
I to jest online !
Nick Westgate

Na szczęście narzędzie ewoluowało do tego stopnia, że ​​znajduje również pozostały błąd.
tripleee

3

Zainstaluj VSCode , a następnie dodaj rozszerzenie debugowania bash i jesteś gotowy do debugowania w trybie wizualnym. zobacz tutaj w akcji.

wprowadź opis obrazu tutaj


3

Użyj zaćmienia z powłoką wtyczek i basheclipse.

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

Dla powłoki: pobierz plik zip i zaimportuj go do eclipse za pomocą pomocy -> zainstaluj nowe oprogramowanie: archiwum lokalne Dla basheclipse: skopiuj jars do katalogu dropins w eclipse

Postępuj zgodnie z instrukcjami https://sourceforge.net/projects/basheclipse/files/?source=navbar

wprowadź opis obrazu tutaj

Napisałem samouczek z wieloma zrzutami ekranu na http://dietrichschroff.blogspot.de/2017/07/bash-eniring-eclipse-for-bash.html


2
To jest odpowiedź z pogranicza tylko linków (zobacz także tutaj ). Powinieneś rozszerzyć swoją odpowiedź, tak aby zawierała jak najwięcej informacji, przynajmniej minimum potrzebne do realizacji tego, co sugerujesz, i użyj linków tylko w celach informacyjnych. Zasadniczo posty na Stack Overflow (i wszystkie Stack Exchange) muszą być niezależne. Oznacza to, że odpowiedź musi zawierać wystarczającą ilość informacji, aby czytelnik nie musiał wychodzić z witryny w celu uzyskania wskazówek. W tej chwili tak nie jest w przypadku tej odpowiedzi.
Makyen

jest to pierwsza odpowiedź, jaką znalazłem po przyjrzeniu się wielu, która faktycznie pokazuje, że prawdziwe debugowanie jest możliwe. Standardowe odpowiedzi „set + x” doskonale pasują do samodzielnej odpowiedzi, ale prawie świadomie ignorują prawdziwe pytania dotyczące prawdziwego debugowania. Przyklaskuję tej odpowiedzi 👏
simbo1905

2

Zbudowałem debugger Bash. Po prostu daj temu szansę. Mam nadzieję, że pomoże https://sourceforge.net/projects/bashdebugingbash


BDB jest obecnie obsługiwane w językach angielskim i hiszpańskim. Aby zmienić język, edytuj plik / etc / default / bdb
abadjm

zrzut ekranu wygląda interesująco, ale nie udało mi się go uruchomić "bdb.sh: wiersz 32: bdbSTR [1]: zmienna niezwiązana"; btw czy pokaże aktualne wartości wszystkich ustawionych zmiennych w każdym kroku, jaki wykonujemy w kodzie?
Aquarius Power

2

set + x = @ECHO OFF, set -x = @ECHO ON.


Możesz dodać -xvopcję do standardowego Shebanga w następujący sposób:

#!/bin/bash -xv  

-x: Wyświetla polecenia i ich argumenty w trakcie ich wykonywania.
-v: Wyświetla linie wejściowe powłoki w trakcie ich czytania.


ltracejest kolejnym narzędziem Linux podobnym do strace. Jednak ltracezawiera listę wszystkich wywołań biblioteki wywoływanych w pliku wykonywalnym lub działającym procesie. Sama nazwa pochodzi od śledzenia wywołań bibliotecznych. Na przykład:

ltrace ./executable <parameters>  
ltrace -p <PID>  

Źródło



1

Jakaś sztuczka do debugowania skrypty:

Za pomocą set -[nvx]

Oprócz

set -x

i

set +x

za zatrzymanie zrzutu.

Chciałbym mówić o tym, set -vktóry zrzut jest mniejszy niż mniej rozwinięta produkcja.

bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l
21

for arg in x v n nx nv nvx;do echo "- opts: $arg"
    bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
        set -$arg
        for i in {0..9};do
            echo $i
          done
        set +$arg
        echo Done.
eof
    sleep .02
  done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

Zrzuć zmienne lub śledzenie w locie

Do testowania niektórych zmiennych używam czasami tego:

bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args

za dodanie:

declare >&2 -p var1 var2

w linii 18. i uruchamiając wynikowy skrypt (z argumentami ), bez konieczności ich edycji.

oczywiście można to wykorzystać do dodania set [+-][nvx]:

bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args

doda declare -p v1 v2 >&2po linii 18, set -xprzed linią 22 i set +xprzed linią 26.

mała próbka:

bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <(
        seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2
arg1 arg2, 1
arg1 arg2, 2
declare -i LINENO="3"
declare -- i="2"
/dev/fd/63: line 3: declare: v2: not found
arg1 arg2, 3
declare -i LINENO="5"
declare -- i="3"
/dev/fd/63: line 5: declare: v2: not found
arg1 arg2, 4
+ echo arg1 arg2, 5
arg1 arg2, 5
+ echo arg1 arg2, 6
arg1 arg2, 6
+ set +x
arg1 arg2, 7
arg1 arg2, 8

Uwaga: Pielęgnacja o $LINENOwpłynie on-the-fly modyfikacje!

(Aby zobaczyć wynikowy skrypt bez wykonywania, po prostu upuść bash <(i ) arg1 arg2)

Krok po kroku, czas wykonania

Spójrz na moją odpowiedź dotyczącą profilowania skryptów bash


0

Jest dużo szczegółów dotyczących rejestrowania skryptów powłoki za pośrednictwem globalnych zmiennych powłoki. Możemy emulować podobny rodzaj logowania w skrypcie powłoki: http://www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

W poście znajdują się szczegółowe informacje o wprowadzaniu poziomów dziennika, takich jak INFO, DEBUG, ERROR. Śledzenie szczegółów, takich jak wpis skryptu, wyjście skryptu, wejście funkcji, wyjście funkcji.

Przykładowy dziennik:

wprowadź opis obrazu tutaj

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.