how to get the original caller lineno when executing a function returning a non-zero value

浪尽此生 提交于 2019-12-14 03:46:33

问题


I've made a func.sh script to be sourced containing:

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. }

Then I've made a main.sh script

1. #!/bin/bash
2.
3. source 'func.sh'
4. testfunc
5.
6. exit 0

My goal is to catch lineno 4 (in the above script), where I haven't managed correctly the returning value.

To do that I tried:

 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

Here I would like to catch the lineno 23.
The output is:

--> TESTFUNC CALLED
23 main import.sh
now I return a non-zero value
--> EXIT HANDLER
BACKTRACE IS:
1 main.sh
PASSED LINENO IS: 1

The correct lineno is detected by caller inside the function itself, but not in the trap, where the name of the script is correct (main.sh) but not the lineno (1???? instead of 22)

I also tried

 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

but the output is:

--> TESTFUNC CALLED
21 main import.sh
now I return a non-zero value
--> ERR HANDLER
BACKTRACE IS:
8 main.sh
PASSED LINENO IS: 8

The caller inside the function itself is still detecting the right lineno (21 in this case), but the situation inside the trap is even worst because it's getting the lineno 8 which is the line inside func.sh where there's the return 1 ... (while the caller inside the trap refers the line to the wrong script main.sh).

At this point I ran out of ideas...


回答1:


I solved in this way:

 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


The output will be

--> TESTFUNC CALLED
57 main import.sh
now I return a non-zero value
--> ERR HANDLER
LINENO: 57
FILE: main.sh

I followed the suggestion of this question on superuser.
Basically I execute a function (preexec) before any command and I store the information of the caller. When an error occurs I read the information over the last caller if I receive a lineno of 1 in the exit trap (which is always wrong, since the first line of any script should be #!/bin/bash)




回答2:


I think BASH_LINENO variable might be what you need. Look here for details: https://www.gnu.org/software/bash/manual/bashref.html#Bash-Variables



来源:https://stackoverflow.com/questions/13213254/how-to-get-the-original-caller-lineno-when-executing-a-function-returning-a-non

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!