debugowanie skryptu Bash

przegląd

w tym samouczku przyjrzymy się różnym technikom debugowania skryptów powłoki Bash. Powłoka Bash nie zapewnia żadnego wbudowanego debugera. Istnieją jednak pewne polecenia i konstrukcje, które można wykorzystać do tego celu.

najpierw omówimy zastosowanie polecenia set do debugowania skryptów. Następnie sprawdzimy kilka debugowania konkretnych przypadków użycia za pomocą poleceń set i trap. Na koniec przedstawimy kilka metod debugowania już uruchomionych skryptów.

Opcje debugowania Bash

opcje debugowania dostępne w powłoce Bash mogą być włączane i wyłączane na wiele sposobów. W skryptach możemy użyć polecenia set lub dodać opcję do linii shebang. Jednak inne podejście polega na jawnym określeniu opcji debugowania w wierszu poleceń podczas wykonywania skryptu. Przejdźmy do dyskusji.

2.1. Włączenie trybu gadatliwego

możemy włączyć tryb gadatliwy za pomocą przełącznika-v, który pozwala nam przeglądać każde polecenie przed jego wykonaniem.

aby to zademonstrować, stwórzmy przykładowy skrypt:

#! /bin/bashread -p "Enter the input: " valzero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fi

ten skrypt sprawdza, czy liczba wprowadzona jako wejście jest dodatnia.

następnie wykonajmy nasz skrypt:

$ bash -v ./positive_check.sh#! /bin/bashread -p "Enter the input: " valEnter the input: -10zero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fiThe input value is not positive.

jak możemy zauważyć, drukuje każdą linię skryptu na terminalu, zanim zostanie przetworzony.

możemy również dodać opcję-v w wierszu:

#! /bin/bash -v

ma to taki sam efekt jak jawne wywołanie skryptu za pomocą bash-v. innym odpowiednikiem jest włączenie trybu w skrypcie za pomocą polecenia set:

#! /bin/bashset -v

w rzeczywistości możemy użyć jednego ze sposobów omówionych powyżej, aby włączyć różne przełączniki, które będziemy odtąd omawiać.

2.2. Sprawdzanie składni przy użyciu trybu noexec

mogą się zdarzyć sytuacje, w których będziemy chcieli zweryfikować składnię skryptu przed jego wykonaniem. Jeśli tak, możemy użyć trybu noexec używając opcji-n. W rezultacie Bash odczytuje polecenia, ale nie wykonuje ich.

Wykonajmy nasze positive_check.sh skrypt w trybie noexec:

$ bash -n ./positive_check.sh

spowoduje to puste wyjście, ponieważ nie ma błędów składniowych. Teraz zmodyfikujemy trochę nasz skrypt i usuniemy instrukcję then:

#! /bin/bashread -p "Enter the input: " valzero_val=0if echo "Positive number entered."else echo "The input value is not positive."fi

następnie sprawdzimy ją składniowo za pomocą opcji-n:

$ bash -n ./positive_check_noexec.sh./positive_check_noexec.sh: line 6: syntax error near unexpected token `else'./positive_check_noexec.sh: line 6: ` else'

zgodnie z oczekiwaniami, wystąpił błąd, ponieważ przegapiliśmy instrukcję then w warunku if.

2.3. Debugowanie w trybie xtrace

w poprzedniej sekcji przetestowaliśmy skrypt pod kątem błędów składniowych. Ale w celu identyfikacji błędów logicznych, możemy chcieć prześledzić stan zmiennych i poleceń podczas procesu wykonywania. W takich przypadkach możemy wykonać skrypt w trybie xtrace (execution trace) używając opcji-x.

ten tryb wyświetla ślad poleceń dla każdej linii po ich rozwinięciu, ale przed ich wykonaniem.

Wykonajmy nasze positive_check.sh skrypt w trybie śledzenia wykonania:

$ bash -x ./positive_check.sh+ read -p 'Enter the input: ' valEnter the input: 17+ zero_val=0+ ''+ echo 'Positive number entered.'Positive number entered.

tutaj możemy zobaczyć rozszerzoną wersję zmiennych na stdout przed wykonaniem. Ważne jest, aby pamiętać, że linie poprzedzone znakiem + są generowane przez tryb xtrace.

2.4. Identyfikacja Nie ustawionych zmiennych

Uruchom eksperyment, aby zrozumieć domyślne zachowanie nie ustawionych zmiennych w skryptach Bash:

#! /bin/bashfive_val=5two_val=2total=$((five_val+tow_val))echo $total

teraz wykonamy powyższy skrypt:

$ ./add_values.sh5

jak możemy zauważyć, wystąpił problem: skrypt został pomyślnie wykonany, ale wynik jest logicznie nieprawidłowy.

wykonamy teraz skrypt z opcją-u:

$ bash -u ./add_values.sh./add_values.sh: line 4: tow_val: unbound variable

oczywiście, teraz jest o wiele więcej jasności!

skrypt nie został wykonany, ponieważ zmienna tow_val nie jest zdefiniowana. Błędnie wpisaliśmy two_val jako tow_val podczas obliczania sumy.

opcja-u traktuje nie ustawione zmienne i parametry jako błąd podczas rozszerzania parametrów. W rezultacie otrzymujemy komunikat o błędzie, że zmienna nie jest powiązana z wartością podczas wykonywania skryptu z opcją-u

przypadki użycia do debugowania skryptów powłoki

do tej pory widzieliśmy różne przełączniki do debugowania skryptów. Odtąd przyjrzymy się niektórym przypadkom użycia i metodom implementowania ich w skryptach powłoki.

3.1. Łączenie opcji debugowania

aby uzyskać lepszy wgląd, możemy dalej łączyć różne opcje polecenia set.

Wykonajmy nasze add_values.sh skrypt z włączonymi opcjami-v i-u:

$ bash -uv ./add_values.sh#! /bin/bashfive_val=5two_val=2total=$((five_val+tow_val))./add_values.sh: line 4: tow_val: unbound variable

tutaj, włączając tryb gadatliwy z opcją-u, możemy łatwo zidentyfikować polecenie wyzwalające błąd.

Podobnie, możemy połączyć tryb verbose i xtrace, aby uzyskać bardziej precyzyjne informacje o debugowaniu.

jak wspomniano wcześniej, opcja-v pokazuje każdą linię przed jej obliczeniem, a opcja-x pokazuje każdą linię po ich rozwinięciu. Dlatego możemy połączyć opcje-x I-v, aby zobaczyć, jak wyglądają wyrażenia przed i po podstawieniu zmiennej.

teraz Wykonajmy nasze positive_check.sh skrypt z włączonymi trybami-x I-v:

$ bash -xv ./positive_check.sh#! /bin/bashread -p "Enter the input: " val+ read -p 'Enter the input: ' valEnter the input: 5zero_val=0+ zero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fi+ ''+ echo 'Positive number entered.'Positive number entered.

możemy zauważyć, że instrukcje są drukowane na stdout przed i po rozszerzeniu zmiennej.

3.2. Debugowanie określonych części skryptu

debugowanie za pomocą opcji-x lub-v skryptów powłoki generuje wyjście dla każdej instrukcji na standardowym wyjściu. Mogą jednak zdarzyć się sytuacje, w których będziemy chcieli zredukować informacje o debugowaniu tylko do określonych części skryptu. Możemy to osiągnąć poprzez włączenie trybu debugowania przed uruchomieniem bloku kodu, a następnie zresetowanie go za pomocą polecenia set.

sprawdźmy to na przykładzie:

#! /bin/bashread -p "Enter the input: " valzero_val=0set -xif then echo "Positive number entered."else echo "The input value is not positive."fiset +xecho "Script Ended" 

tutaj możemy debugować tylko warunek if za pomocą instrukcji set przed rozpoczęciem warunku. Później możemy zresetować tryb xtrace po zakończeniu bloku if za pomocą polecenia set + X.

zweryfikuj to wyjściem:

$ ./positive_debug.shEnter the input: 7+ ''+ echo 'Positive number entered.'Positive number entered.+ set +xScript Ended

z pewnością wyjście wygląda na mniej zaśmiecone.

3.3. Przekierowanie tylko wyjścia debugowania do pliku

w poprzedniej sekcji zbadaliśmy, w jaki sposób możemy ograniczyć debugowanie tylko do niektórych części skryptu. W związku z tym, możemy ograniczyć ilość danych wyjściowych na stdout.

Ponadto możemy przekierować informacje o debugowaniu do innego pliku i pozwolić, aby wyjście skryptu wydrukowało się na standardowym wyjściu.

stwórzmy kolejny skrypt, aby go sprawdzić:

#! /bin/bashexec 5> debug.log PS4='$LINENO: ' BASH_XTRACEFD="5" read -p "Enter the input: " valzero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fi

najpierw otworzyliśmy debugowanie.plik dziennika na deskryptorze pliku (FD) 5 do zapisu za pomocą polecenia exec.

następnie zmieniliśmy specjalną zmienną powłoki PS4. Zmienna PS4 definiuje znak zachęty, który zostanie wyświetlony, gdy wykonamy skrypt powłoki w trybie xtrace. Domyślną wartością PS4 jest +. Zmieniliśmy wartość zmiennej PS4, aby wyświetlać numery linii w wierszu polecenia debugowania. Aby to osiągnąć, użyliśmy innego specjalnego shell variable LINENO.

później przypisaliśmy FD 5 do zmiennej Bash BASH_XTRACEFD. W efekcie, Bash napisze teraz wyjście xtrace na FD5 tj. debugowanie.plik dziennika. Wykonajmy skrypt:

$ bash -x ./debug_logging.sh+ exec+ PS4='$LINENO: '4: BASH_XTRACEFD=5Enter the input: 2Positive number entered.

zgodnie z oczekiwaniami, wyjście debugowania nie jest zapisywane na terminalu. Chociaż wypisano kilka pierwszych linii, dopóki FD 5 nie zostanie przypisane do wyjścia debugowania.

dodatkowo skrypt tworzy również debugowanie pliku wyjściowego.log, który zawiera informacje o debugowaniu:

$ cat debug.log5: read -p 'Enter the input: ' val6: zero_val=07: ''9: echo 'Positive number entered.'

debugowanie skryptów za pomocą pułapki

możemy wykorzystać funkcję debugowania pułapki Basha do powtarzalnego wykonywania polecenia. Polecenie określone w argumentach polecenia trap jest wykonywane przed każdym kolejnym poleceniem w skrypcie.

zilustrujmy to przykładem:

#! /bin/bashtrap 'echo "Line- ${LINENO}: five_val=${five_val}, two_val=${two_val}, total=${total}" ' DEBUGfive_val=5two_val=2total=$((five_val+two_val))echo "Total is: $total"total=0 && echo "Resetting Total"

w tym przykładzie podaliśmy polecenie echo do wypisania wartości zmiennych five_val, two_val i total. Następnie przekazaliśmy to polecenie echo do komendy trap z sygnałem debugowania. W efekcie, przed wykonaniem każdego polecenia w skrypcie, wypisywane są wartości zmiennych.

sprawdźmy wygenerowane wyjście:

$ ./trap_debug.shLine- 3: five_val=, two_val=, total=Line- 4: five_val=5, two_val=, total=Line- 5: five_val=5, two_val=2, total=Line- 6: five_val=5, two_val=2, total=7Total is: 7Line- 7: five_val=5, two_val=2, total=7Line- 7: five_val=5, two_val=2, total=0Resetting Total

debugowanie już uruchomionych skryptów

do tej pory przedstawiliśmy metody debugowania skryptów powłoki podczas ich wykonywania. Teraz przyjrzymy się sposobom debugowania już uruchomionego skryptu.

rozważ przykładowy skrypt, który wykonuje sleep w nieskończonej pętli while:

#! /bin/bashwhile :do sleep 10 & echo "Sleeping for 4 seconds.." sleep 4done

za pomocą polecenia pstree możemy sprawdzić procesy potomne rozwidlone przez nasz skrypt sleep.sh:

$ pstree -pinit(1)─┬─init(148)───bash(149)───sleep.sh(372)─┬─sleep(422) │ ├─sleep(424) │ └─sleep(425) ├─init(213)───bash(214)───pstree(426) └─{init}(7)

użyliśmy dodatkowej opcji-p, aby wydrukować identyfikatory procesów wraz z nazwami procesów. Dzięki temu jesteśmy w stanie uświadomić sobie, że skrypt czeka na zakończenie procesów potomnych (uśpienia).

czasami możemy chcieć przyjrzeć się bliżej operacjom wykonywanym przez nasze procesy. W takich przypadkach możemy użyć polecenia strace do śledzenia bieżących wywołań systemowych Linuksa:

$ sudo strace -c -fp 372strace: Process 372 attachedstrace: Process 789 attachedstrace: Process 790 attached^Cstrace: Process 372 detachedstrace: Process 789 detachedstrace: Process 790 detached% time seconds usecs/call calls errors syscall------ ----------- ----------- --------- --------- ----------------100.00 0.015625 5208 3 wait4 0.00 0.000000 0 6 read 0.00 0.000000 0 1 write 0.00 0.000000 0 39 close 0.00 0.000000 0 36 fstat 0.00 0.000000 0 38 mmap 0.00 0.000000 0 8 mprotect 0.00 0.000000 0 2 munmap 0.00 0.000000 0 6 brk 0.00 0.000000 0 16 rt_sigaction 0.00 0.000000 0 20 rt_sigprocmask 0.00 0.000000 0 1 rt_sigreturn 0.00 0.000000 0 6 6 access 0.00 0.000000 0 1 dup2 0.00 0.000000 0 2 getpid 0.00 0.000000 0 2 clone 0.00 0.000000 0 2 execve 0.00 0.000000 0 2 arch_prctl 0.00 0.000000 0 37 openat------ ----------- ----------- --------- --------- ----------------100.00 0.015625 228 6 total

tutaj użyliśmy opcji-p, aby dołączyć do ID procesu (372), czyli naszego skryptu w trakcie wykonywania. Dodatkowo użyliśmy opcji-f, aby dołączyć do wszystkich procesów potomnych. Zauważ, że polecenie strace generuje dane wyjściowe dla każdego wywołania systemowego. Dlatego użyliśmy opcji – c, aby wydrukować podsumowanie wywołań systemowych po zakończeniu strace.

wniosek

w tym samouczku, studiowaliśmy wiele technik debugowania skryptu powłoki.

na początku omówiliśmy różne opcje polecenia set i ich użycie do debugowania skryptów. Następnie wdrożyliśmy kilka studiów przypadków, aby zbadać kombinację opcji debugowania. Oprócz tego zbadaliśmy również sposoby ograniczenia wyjścia debugowania i przekierowania go do innego pliku.

następnie przedstawiliśmy przypadek użycia polecenia trap i sygnału debugowania dla scenariuszy debugowania. Na koniec zaproponowaliśmy kilka podejść do debugowania już uruchomionych skryptów.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.

Previous post Przeciwstawianie się królowi: jak Bitwa pod Arsuf została wygrana
Next post Birds Eye View Porady fotograficzne