加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读