bash – 如何在执行返回非零值的函数时获取原始调用者lineno
发布时间:2020-12-15 21:05:50 所属栏目:安全 来源:网络整理
导读:我已经制作了一个func.sh脚本,其中包含: 1. function testfunc ()2. {3. echo "-- TESTFUNC CALLED"4. caller 05.6. # here I mimic that something went wrong7. echo "now I return a non-zero value"8. return 19. } 然后我做了一个main.sh脚本 1. #!/bi
我已经制作了一个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 我的目标是捕获lineno 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 在这里,我想赶上lineno 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 函数本身内部的调用者检测到正确的lineno,但脚本中的名称是正确的(main.sh)而不是lineno(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 函数内部的调用者仍然检测到正确的lineno(在这种情况下为21),但陷阱内部的情况甚至更糟,因为它获取了lineno 8,这是func.sh中的行,其中返回1 … (虽然陷阱内的调用者将该行引用到错误的脚本main.sh). 在这一点上,我没有想法…… 解决方法
我这样解决了:
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 我在超级用户上遵循了this question的建议.基本上我在任何命令之前执行一个函数(preexec)并存储调用者的信息.当发生错误时,如果我在退出陷阱中收到lineno为1,则读取最后一个调用者的信息(这总是错误的,因为任何脚本的第一行应该是#!/ bin / bash) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |