Як знайти номер рядка в Bash, коли сталася помилка?


21

Як знайти номер рядка в Bash, де сталася помилка?

Приклад

Я створюю наступний простий скрипт з номерами рядків, щоб пояснити, що нам потрібно. Сценарій буде копіювати файли з

cp $file1 $file2
cp $file3 $file4

Якщо одна з cpкоманд виходить з ладу, функція вийде з виходом 1 . Ми хочемо додати можливість функції також друкувати помилку з номером рядка (наприклад, 8 або 12).

Чи можливо це?

Зразок сценарію

1 #!/bin/bash
2
3
4 function in_case_fail {
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6 }
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14


Ви можете використовувати set -xта / або set -vвідстежувати, що було виконано. Не зовсім те, про що ви просили, але це, мабуть, також буде корисно.
Рольф

Відповіді:


29

Замість того, щоб використовувати вашу функцію, я використовую цей метод замість цього:

$ cat yael.bash
#!/bin/bash

set -eE -o functrace

file1=f1
file2=f2
file3=f3
file4=f4

failure() {
  local lineno=$1
  local msg=$2
  echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR

cp -- "$file1" "$file2"
cp -- "$file3" "$file4"

Це працює, перехоплюючи ERR, а потім викликаючи failure()функцію за допомогою поточного номера рядка + команда bash, яка була виконана.

Приклад

Тут я не прийняв ніякого догляду , щоб створити файли, f1, f2, f3, або f4. Коли я запускаю описаний вище сценарій:

$ ./yael.bash
cp: cannot stat f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"

Він не вдається, повідомляючи номер рядка плюс команду, яка була виконана.


14

Крім того, що LINENOмістить номер поточного рядка, є BASH_LINENOі FUNCNAMEBASH_SOURCE) масиви, які містять назви функцій та номери рядків, з яких вони викликані.

Отже, ви можете зробити щось подібне:

#!/bin/bash

error() {
        printf "'%s' failed with exit code %d in function '%s' at line %d.\n" "${1-something}" "$?" "${FUNCNAME[1]}" "${BASH_LINENO[0]}"
}

foo() {
        ( exit   0 ) || error "this thing"
        ( exit 123 ) || error "that thing"
}

foo

Запуск, який би надрукував

'that thing' failed with exit code 123 in function 'foo' at line 9.

Якщо ви використовуєте set -eабо trap ... ERRавтоматично виявляєте помилки, зверніть увагу, що вони мають деякі застереження. Також важче включити опис того, що робив сценарій у той час (як ви робили у своєму прикладі), хоча це може бути кориснішим для звичайного користувача, ніж просто номер рядка.

Дивіться, наприклад, такі питання щодо питань set -eта інших:


13

У Bash є вбудована змінна, $LINENOяка замінюється поточним номером рядка в операторі, так що ви можете це зробити

in_case_fail $? "at $LINENO: cp $file1 $file2"

Ви також можете спробувати використовувати trap ... ERRзапуски, коли команда не працює (якщо результат не перевіряється). Наприклад:

trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR

Тоді якщо така команда cp $file1 $file2не вдасться, ви отримаєте повідомлення про помилку з номером рядка та виходом. Ви також знайдете команду з помилкою в змінній $BASH_COMMAND(хоча не будь-які переадресації тощо).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.