Jak wyświetlić numer linii podczas wykonywania skryptu bash

89

Mam skrypt testowy, który ma wiele poleceń i generuje dużo danych wyjściowych, używam set -xlub set -vi set -e, więc skrypt zatrzymywał się, gdy wystąpił błąd. Jednak nadal jest mi dość trudno zlokalizować, która linia spowodowała zatrzymanie wykonywania w celu zlokalizowania problemu. Czy istnieje metoda, która może wyświetlić numer wiersza skryptu przed wykonaniem każdego wiersza? Lub wyprowadzić numer wiersza przed wyświetleniem poleceń wygenerowanym przez set -x? Lub każda metoda, która może rozwiązać mój problem z lokalizacją linii skryptu, byłaby bardzo pomocna. Dzięki.

dspjm
źródło

Odpowiedzi:

159

Wspomniałeś, że już używasz -x. Zmienna PS4oznacza, że ​​wartość jest monitem wyświetlanym przed wyświetleniem wiersza polecenia, gdy -xopcja jest ustawiona i domyślnie :następuje spacja.

Możesz zmienić, PS4aby emitować LINENO(numer wiersza w aktualnie wykonywanej skrypcie lub funkcji powłoki).

Na przykład, jeśli twój skrypt czyta:

$ cat script
foo=10
echo ${foo}
echo $((2 + 2))

Wykonanie go w ten sposób wypisze numery wierszy:

$ PS4='Line ${LINENO}: ' bash -x script
Line 1: foo=10
Line 2: echo 10
10
Line 3: echo 4
4

http://wiki.bash-hackers.org/scripting/debuggingtips daje ostateczną wersję, PS4która wypisze wszystko, czego będziesz potrzebować do śledzenia:

export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
devnull
źródło
4
Zastanawiam się, dlaczego nikt nie wspomina o tym przy „Jak debugować skrypty powłoki?” . To jest o wiele lepsze niż tylkoecho
Suvarna Pattayil
@VusP Zgoda, echonajlepiej unikać niepotrzebnych wypowiedzi.
devnull
2
Nie mogę się powstrzymać od poczucia, że -x powinno to wypisać numery wierszy. A może - nx powinien zawierać numery linii. Dla mnie to jeden z tych „WTF” momentów ...
jww
1
Człowieku, żałuję, że nie wiedziałem o tej miksturze na PS4 wcześniej ... Uratowałoby mi tyle bólów głowy
niken
2
\033[0;33m+(${BASH_SOURCE}:${LINENO}):\033[0m ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'dla niektórych kolorów
Ulysse BN,
34

W Bash $LINENOzawiera numer wiersza, w którym skrypt jest obecnie wykonywany.

Jeśli chcesz znać numer wiersza, w którym funkcja została wywołana, spróbuj $BASH_LINENO. Zauważ, że ta zmienna jest tablicą.

Na przykład:

#!/bin/bash       

function log() {
    echo "LINENO: ${LINENO}"
    echo "BASH_LINENO: ${BASH_LINENO[*]}"
}

function foo() {
    log "$@"
}

foo "$@"

Zobacz tutaj, aby uzyskać szczegółowe informacje na temat zmiennych Bash.

Deqing
źródło
0

Proste (ale wydajne) rozwiązanie: Umieść echowokół kodu, który Twoim zdaniem powoduje problem i przesuwaj echowiersz po wierszu, aż komunikaty nie pojawią się już na ekranie - ponieważ skrypt zatrzymał się z powodu wcześniejszego błędu.

Jeszcze potężniejsze rozwiązanie: zainstaluj bashdbdebuger bash i debuguj skrypt wiersz po wierszu

hek2mgl
źródło
2
echow wielu przypadkach może pomóc, ale nie wystarczy, gdy spróbujesz zastosować je w funkcjach, które mają sensowne, analizowalne wyniki.
Eliran Malka,
1
@EliranMalka Fair point. W takim przypadku echo "foo" >&2
możesz wysłać
1
... należy odbijać echo do stderr we wszystkich przypadkach, gdy celem są komunikaty diagnostyczne.
Charles Duffy,
0

Obejście problemu dla muszli bez LINENO

W dość wyrafinowanym skrypcie nie chciałbym widzieć wszystkich numerów linii; raczej chciałbym mieć kontrolę nad produkcją.

Zdefiniuj funkcję

echo_line_no () {
    grep -n "$1" $0 |  sed "s/echo_line_no//" 
    # grep the line(s) containing input $1 with line numbers
    # replace the function name with nothing 
} # echo_line_no

Użyj go z cudzysłowami, takimi jak

echo_line_no "this is a simple comment with a line number"

Wyjście jest

16   "this is a simple comment with a line number"

jeśli numer tej linii w pliku źródłowym wynosi 16.

To w zasadzie odpowiada na pytanie, jak wyświetlić numer linii podczas wykonywania skryptu bash dla użytkowników ash lub innych powłok bez LINENO.

Coś więcej do dodania?

Pewnie. Dlaczego tego potrzebujesz? Jak z tym pracujesz? Co możesz z tym zrobić? Czy to proste podejście jest naprawdę wystarczające lub przydatne? Dlaczego w ogóle chcesz przy tym majstrować?

Chcieć wiedzieć więcej? Przeczytaj uwagi na temat debugowania

kklepper
źródło