Jak debugować skrypt bash?


135

Mam pewne problemy z niektórymi skryptami w bash, dotyczące błędów i nieoczekiwanych zachowań. Chciałbym zbadać przyczyny problemów, aby móc zastosować poprawki. Czy istnieje sposób, w jaki mogę włączyć jakiś „tryb debugowania” dla bash, aby uzyskać więcej informacji?

Odpowiedzi:


132

Uruchom skrypt bash bash -x ./script.shlub dodaj go, set -xaby wyświetlić wyniki debugowania.


Dodatkowo w wersji bash4.1 lub nowszej:

Jeśli chcesz zapisać dane wyjściowe debugowania w osobnym pliku, dodaj to do skryptu:

exec 5> debug_output.txt
BASH_XTRACEFD="5"

Zobacz: https://stackoverflow.com/a/25593226/3776858


Jeśli chcesz zobaczyć numery linii, dodaj to:

PS4='$LINENO: '


Jeśli masz dostęp do loggerkomendy, możesz użyć tego do zapisania wyniku debugowania za pośrednictwem syslog ze znacznikiem czasu, nazwą skryptu i numerem wiersza:

#!/bin/bash

exec 5> >(logger -t $0)
BASH_XTRACEFD="5"
PS4='$LINENO: '
set -x

# Place your code here

Można użyć opcji -pz loggerpoleceniem, aby ustawić indywidualne usługi i poziom pisać wyjście za pośrednictwem lokalnych syslog do własnego pliku dziennika.


7
-v może również pomóc (wypisuje każdą linię w trakcie wykonywania. można łączyć z -x). Zobacz także: bashdb.sourceforge.net
Olivier Dulac

4
innym wspaniałym zasobem jest: shellcheck.net
Olivier Dulac

Co robi „exec 5>”?
aggsol

3
@aggsol: Jeśli używasz BASH_XTRACEFD="5"bash, zapisuje dane wyjściowe śledzenia wygenerowane, gdy set -xjest włączony do deskryptora pliku 5. exec 5> >(logger -t $0)przekierowuje dane wyjściowe z deskryptora pliku 5 do loggerpolecenia.
Cyrus

1
Zastanawiam się, czy możesz uzyskać numer linii i ścieżkę skryptu powłoki lub nazwę w PS4?
iloveretards

55

Za pomocą set -x

Zawsze używam set -xi set +x. Możesz zawinąć obszary, które chcesz zobaczyć, co się z nimi dzieje, aby zwiększyć / zmniejszyć szczegółowość.

#!/bin/bash

set -x
..code to debug...
set +x

log4bash

Również jeśli wykonałeś prace programistyczne i znasz styl programów rejestrujących o nazwach log4j, log4perl itp., Możesz skorzystać z log4bash .

fragment

Spójrzmy prawdzie w oczy - zwykłe stare echo po prostu go nie wycina. log4bash to próba lepszego rejestrowania skryptów Bash (tzn. ograniczenie logowania Bash do minimum).

Stamtąd możesz robić takie rzeczy w skryptach Bash:

#!/usr/bin/env bash
source log4bash.sh

log "This is regular log message... log and log_info do the same thing";

log_warning "Luke ... you turned off your targeting computer";
log_info "I have you now!";
log_success "You're all clear kid, now let's blow this thing and go home.";
log_error "One thing's for sure, we're all gonna be a lot thinner.";

# If you have figlet installed -- you'll see some big letters on the screen!
log_captains "What was in the captain's toilet?";

# If you have the "say" command (e.g. on a Mac)
log_speak "Resistance is futile";

Wynikające z tego rodzaju wyników:

    ss1

log4sh

Jeśli potrzebujesz czegoś bardziej przenośnego, są też starsze log4sh. Działa podobnie log4bash, dostępny tutaj:


W systemie Ubuntu mam alias say="spd-say"plik .bashrc, który imituje saypolecenie z innych dystrybucji lub systemu OS X.
Doorknob

1
set -vx byłby dobrą kombinacją, gdyby był używany z debugowaniem trap-trap read. To pozwala ci przechodzić obok linii i wyświetlać wyniki
Magnus Melwin

34

Istnieje debugger bash, bashdb , który jest instalowalnym pakietem na wielu dystrybucjach. Używa wbudowanego rozszerzonego trybu debugowania bash ( shopt -s extdebug). Wygląda bardzo podobnie do gdb; Oto przykładowa sesja, która doda smaku:

$ ls
1st.JPG  2ndJPG.JPG
$ cat ../foo.sh
for f in *.JPG
do
  newf=${f/JPG/jpg}
  mv $f $newf
done
$ bashdb ../foo.sh
(foo.sh:1):
1:      for f in *.JPG
bashdb<0> next
(foo.sh:3):
3:        newf=${f/JPG/jpg}
bashdb<1> next
(foo.sh:4):
4:        mv $f $newf

Podobnie jak w gdb, instrukcja jest wyświetlana tuż przed jej wykonaniem. Możemy więc badać zmienne, aby zobaczyć, co zrobi instrukcja, zanim to zrobi.

bashdb<2> print $f $newf
1st.JPG 1st.jpg
bashdb<3> next
(foo.sh:1):
1:      for f in *.JPG
bashdb<4> next
(foo.sh:3):
3:        newf=${f/JPG/jpg}
bashdb<5> next
(foo.sh:4):
4:        mv $f $newf
bashdb<6> print $f $newf
2ndJPG.JPG 2ndjpg.JPG

Nie tego chcemy! Spójrzmy jeszcze raz na rozszerzenie parametru.

bashdb<7> print $f ${f/JPG/jpg}
2ndJPG.JPG 2ndjpg.JPG
bashdb<8> print $f ${f/JPG$/jpg}
2ndJPG.JPG 2ndJPG.JPG
bashdb<9> print $f ${f/%JPG/jpg}
2ndJPG.JPG 2ndJPG.jpg

OK, to działa. Ustawmy newfprawidłową wartość.

bashdb<10> eval newf=${f/%JPG/jpg}
$? is 0
bashdb<11> print $f $newf
2ndJPG.JPG 2ndJPG.jpg

Wygląda dobrze. Kontynuuj skrypt.

bashdb<12> next
Debugged program terminated normally. Use q to quit or R to restart.
$ ls
1st.jpg  2ndJPG.jpg

20

Standardową metodą debugowania skryptów w większości powłok opartych na Bourne, takich jak bash, jest pisanie set -xu góry skryptu. To sprawi, że bash będzie bardziej gadatliwy na temat tego, co jest robione / wykonywane i jak argumenty są oceniane.

-x  Print commands and their arguments as they are executed.

jest to przydatne dla interpretera lub skryptów wewnętrznych. Na przykład:

$ find "$fileloc" -type f -prune "$filename" -print
+ find /var/adm/logs/morelogs -type f -prune '-name *.user' -print
find: unknown predicate '-name *.user'
$ find "$fileloc" -type f -prune $filename -print
+ find /var/adm/logs/morelogs -type f -prune -name '*.user' -print
find: '/var/adm/logs/morelogs': No such file or directory

Powyżej możemy zobaczyć, dlaczego szukanie kończy się niepowodzeniem z powodu niektórych pojedynczych cudzysłowów.

Aby dezaktywować tę funkcję, po prostu wpisz set +x.


13

Korzystanie z Eclipse

Możesz użyć połączonego środowiska Eclipse i Shelled ze skryptem „_DEBUG.sh”, do którego link znajduje się poniżej.

Przełączanie pocisków

Domyślnie narzędzie programistyczne Shelled używa /bin/dashjako interpretera. Zmieniłem to, aby /bin/bashuzyskać lepszą zgodność z większością przykładów powłok w Internecie i moim środowisku.

UWAGA: Możesz to zmienić, przechodząc do: Okno -> Preferencje -> Skrypt powłoki -> Tłumacze

Instrukcje instalacji

Pakiet debuggera zawiera kroki umożliwiające użycie _DEBUG.shskryptu do debugowania skryptu, który jest w zasadzie (readme.txt):

  1. Utwórz projekt Shell Script: Plik -> Nowy -> Inne -> Shell Script -> Kreator projektu Shell Script .
  2. Utwórz plik skryptu Bash: Plik -> Nowy -> Plik . W tym przykładzie tak będzie script.sh. Rozszerzenie powinno być „.sh” i jest koniecznością.
  3. Skopiuj plik _DEBUG.shdo folderu projektu.
  4. Wstaw następujący tekst w górnej części pliku script.sh:

    . _DEBUG.sh
  5. Jeśli plik został utworzony w systemie Microsoft Windows, należy wykonać polecenie Plik -> Konwertuj ograniczniki linii na -> Unix .

  6. Skonfiguruj konfigurację uruchamiania debugowania: Uruchom -> Konfiguracje debugowania -> Skrypt Bash ... Można tu ustawić 2 pola:

    a) „Skrypt Bash:” - Ścieżka w obszarze roboczym Eclipse do skryptu Bash do debugowania.
    e) „Port debuggera:” 33333

  7. Przejdź do perspektywy debugowania. Rozpocznij sesję debugowania. Uruchom script.shz powłoki bash.

Interfejs debugowania bash

wprowadź opis zdjęcia tutaj

Ten debugger bash posiada wszystkie funkcje standardowych debuggerów programistycznych, takich jak:

  • Przełącznik punktu przerwania
  • Pojedyncza operacja krok po kroku
  • Funkcje i podprogramy Step-in, Step-out, Step-over
  • Badanie kodu lub zmiennych w dowolnym momencie podczas działania skryptu

Shelled (Shell Script Editor) IDE (zintegrowane środowisko programistyczne) ma dodatkową zaletę polegającą na sprawdzaniu kontekstu, podświetlaniu i wcięciach podczas pisania skryptu. Jeśli nie zostanie prawidłowo wcięte, możesz od razu oznaczyć tam wiele błędów.

Są też inne korzyści IDE, takie jak:

  • Lista zadań do zrobienia
  • Zadanie Mylyn
  • Lista zakładek
  • Edycja wielu okien
  • Zdalne udostępnianie środowiska

Fajna wskazówka. Miło wiedzieć, że Bash można tak debugować.
slm

8

W ostatnich latach pojawił się wspaniały zasób: http://shellcheck.net

pokazuje więcej niż zwykłe bash, pozwalając łatwo znaleźć te irytujące niezamknięte cytaty lub nawiasy klamrowe itp.

Tylko upewnij się, że nie wklejasz wrażliwych informacji (IP, haseł itp.) W sieci ... (zwłaszcza, że ​​jest to http, niezaszyfrowane) (Wierzę, że shellcheck jest również dostępny do pobrania, ale nie jestem pewien)



5

po prostu użyj:

#!/bin/bash -x

to samo dla powłoki:

#!/bin/sh -x
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.