Как получить исходный вызывающий льнено при выполнении функции, возвращающей ненулевое значение
Я создал скрипт func.sh, содержащий:
1. function testfunc ()
2. {
3. echo "--> TESTFUNC CALLED"
4. caller 0
5.
6. # here I mimic that something went wrong
7. echo "now I return a non-zero value"
8. return 1
9. }
Затем я сделал скрипт main.sh
1. #!/bin/bash
2.
3. source 'func.sh'
4. testfunc
5.
6. exit 0
Моя цель - поймать бельё 4 (в вышеприведённом сценарии), где мне не удалось правильно вернуть возвращаемое значение.
Для этого я попытался:
1. #!/bin/bash
2.
3. set -o errexit
4.
5. function exit_handler ()
6. {
7. echo "--> EXIT HANDLER"
8.
9. echo "BACKTRACE IS:"
10. local i=0
11. while caller $i > /dev/null
12. do
13. caller $i
14. let "i=i+1"
15. done
16.
17. echo "PASSED LINENO IS: $1"
18. exit 0
19. }
20. trap 'exit_handler $LINENO' EXIT
21.
22. source 'func.sh'
23. testfunc
24.
25. exit 0
Здесь я хотел бы поймать бельё 23.
Выход:
--> TESTFUNC CALLED
23 main import.sh
now I return a non-zero value
--> EXIT HANDLER
BACKTRACE IS:
1 main.sh
PASSED LINENO IS: 1
Правильное бельё определяется вызывающей стороной внутри самой функции, но не в ловушке, где имя скрипта правильное (main.sh), но не бельё (1???? вместо 22)
Я тоже пробовал
1. #!/bin/bash
2.
3. function err_handler ()
4. {
5. echo "--> ERR HANDLER"
6.
7. echo "BACKTRACE IS:"
8. local i=0
9. while caller $i > /dev/null
10. do
11. caller $i
12. let "i=i+1"
13. done
14.
15. echo "PASSED LINENO IS: $1"
16. exit 0
17. }
18. trap 'err_handler $LINENO' ERR
19.
20. source 'func.sh'
21. testfunc
22.
23. exit 0
но вывод:
--> TESTFUNC CALLED
21 main import.sh
now I return a non-zero value
--> ERR HANDLER
BACKTRACE IS:
8 main.sh
PASSED LINENO IS: 8
Вызывающая сторона внутри самой функции все еще обнаруживает правильное белье ( в данном случае 21), но ситуация внутри ловушки еще хуже, потому что она получает белье 8, которое является строкой внутри func.sh, где есть возврат 1 ... (в то время как вызывающая сторона внутри ловушки ссылается на строку с неверным сценарием main.sh).
На данный момент у меня закончились идеи...
2 ответа
Я решил таким образом:
1. #!/bin/bash
2.
3. set -o errexit
4.
5. function exit_handler ()
6. {
7. local p_lineno="$1"
8.
9. echo "--> ERR HANDLER"
10.
11. for (( i=${#g_bash_lineno[@]}-1; i>=0; i-- ))
12. do
13. test ${g_bash_lineno[$i]} -ne 1 && break
14. done
15.
16. local g_lineno="${g_bash_lineno[$i]}"
17.
18. if test ${p_lineno} -eq 1 && test ${g_lineno} -gt 1
19. then
20. local lineno="${g_lineno}"
21. else
22. local lineno="${p_lineno}"
23. fi
24.
25. local source="${g_bash_source[-1]}"
26.
27. echo "LINENO: ${lineno}"
28. echo "FILE: ${source}"
29.
30. exit
31. }
32. trap 'exit_handler $LINENO' EXIT
33.
34. function preexec ()
35. {
36. local called=$( caller 0 )
37. local lineno=$( echo "$called" | cut -d " " -f1 )
38. local source=$( echo "$called" | cut -d " " -f3 )
39.
40. if ! eval '[[ ${!g_bash_lineno[@]} ]]' # isset
41. then
42. g_bash_lineno=( "$lineno" )
43. else
44. g_bash_lineno=( "${g_bash_lineno[@]}" "$lineno" )
45. fi
46.
47. if ! eval '[[ ${!g_bash_source[@]} ]]' # isset
48. then
49. g_bash_source=( "$source" )
50. else
51. g_bash_source=( "${g_bash_source[@]}" "$source" )
52. fi
53. }
54. trap 'preexec' DEBUG
55.
56. source 'func.sh'
57. testfunc
58.
59. exit 0
Выход будет
--> TESTFUNC CALLED
57 main import.sh
now I return a non-zero value
--> ERR HANDLER
LINENO: 57
FILE: main.sh
Я последовал предложению этого вопроса на суперпользователя.
Обычно я выполняю функцию (preexec) перед любой командой и сохраняю информацию о вызывающем абоненте. Когда происходит ошибка, я читаю информацию о последнем звонящем, если получаю бельё 1 в выходной ловушке (что всегда неверно, так как первая строка любого скрипта должна быть #!/ Bin/bash)
Я думаю, что переменная BASH_LINENO может быть то, что вам нужно. Подробности смотрите здесь: https://www.gnu.org/software/bash/manual/bashref.html.