How to get the original calling lineno when executing a function that returns a nonzero value

I created a func.sh script file 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 made 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 was not able to correctly return the return value.

For this, 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 lineno 23 .
Output:

 --> 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 the caller inside the function itself, but not in the trap where the correct script name (main.sh) is, but not 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 conclusion:

 --> 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 still detects the correct lineno (21 in this case), but the situation inside the trap is even worse because it gets lineno 8, which is the line inside func.sh where there is a return of 1 ... (at that time as the caller inside the trap refers to the line with the wrong script main.sh).

At the moment, I'm out of ideas ...

+4
source share
2 answers

I decided 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 superuser question .
Basically, I execute the function (preexec) before any command and save the information of the caller. When an error occurs, I read the information on the last caller if I get lineno from 1 in the exit trap (which is always wrong, since the first line of any script should be #! / Bin / bash)

+3
source

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

0
source

Source: https://habr.com/ru/post/1443870/


All Articles