Как найти номер строки в 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.