bash调用程序内建函数无法从导出的函数运行,为什么? [英] bash caller builtin stops working from exported function, why?

查看:50
本文介绍了bash调用程序内建函数无法从导出的函数运行,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 bash 和导出函数给我一个非常奇怪的问题,使我可以可靠地回答内置调用者

I have very strange issues using bash and exported function to give me a reliable answer to the call of the builtin caller.

这是我用来说明此问题的设置:Bash脚本 bar 定义并导出函数 bar1 bar2 bar2 调用 bar1 。 Bash脚本 bar 然后执行bash脚本 foo ,它将调用 bar1

Here's my setup to illustrate this issue: Bash script bar defines and exports function bar1 and bar2. bar2 calls bar1. Bash script bar then execute bash script foo which will call bar1.

然后,仅在 bar1 的呼叫之后,内置的呼叫方才会中断。这正常吗?你能解释为什么吗?您可以简化以下暴露问题的代码吗?

The caller builtin will then break only after the call of bar1. Is this normal ? can you explain why ? can you simplify the following code that exposes the issue ?

要完全清楚,这是在您的系统上重现的方法:构建两个文件:

To be perfectly clear, here's how to reproduce on your system: Build both file:

cd /tmp
cat <<"EOF" > foo 
#!/bin/bash

bar1
EOF
chmod +x foo

cat <<"EOF" > bar 
#!/bin/bash

bar2() {
    echo "$FUNCNAME IN: $(caller 0)" >&2 
} 
export -f bar2

bar1() {
    echo "$FUNCNAME BEFORE: $(caller 0)" >&2
    bar2
    echo "$FUNCNAME AFTER: $(caller 0)" >&2 
}
export -f bar1

./foo
EOF
chmod +x bar

然后您可以摆弄一下:

$ ./bar
bar1 BEFORE: 3 main ./foo
bar2 IN: 
bar1 AFTER: 

我期望(行号可接受的变化):

I expected (with acceptable variations on the line numbers):

$ ./bar
bar1 BEFORE: 9 main ./foo
bar2 IN: 5 bar ./foo
bar1 AFTER: 9 main ./foo

最终,我的问题是:我该如何规避此问题并得到呼叫者 >在所有情况下?

Ultimately, my question would be: how could I circumvent this issue and get the caller in all cases ?

附加信息:


  • bash版本: 4.3.42(1)-发行版(x86_64-pc-linux-gnu)来自ubuntu软件包 4.3-14ubuntu1

  • bash version: 4.3.42(1)-release (x86_64-pc-linux-gnu) from ubuntu package 4.3-14ubuntu1.

推荐答案

这是bash中的 bug 。在版本4.4中已修复该问题。

This is a bug in bash. It was fixed in version 4.4.

存在导出功能时, BASH_SOURCE 变量未正确维护。您可以通过显示 FUNCNAME BASH_SOURCE BASH_LINENO 特殊变量:

In the presence of exported functions, the BASH_SOURCE variable is not properly maintained. You can check it by displaying the contents of the FUNCNAME, BASH_SOURCE, BASH_LINENO special variables:

cd /tmp
cat <<"EOF" > foo 
#!/bin/bash

bar1 
EOF
chmod +x foo

cat <<"EOF" > bar 
#!/bin/bash

bar2() {
    echo "$FUNCNAME IN: $(caller 0) [${FUNCNAME[@]}] [${BASH_SOURCE[@]}] [${BASH_LINENO[@]}]" >&2 
} 
export -f bar2

bar1() {
    echo "$FUNCNAME BEFORE: $(caller 0) [${FUNCNAME[@]}] [${BASH_SOURCE[@]}] [${BASH_LINENO[@]}]" >&2
    bar2
    echo "$FUNCNAME AFTER: $(caller 0) [${FUNCNAME[@]}] [${BASH_SOURCE[@]}] [${BASH_LINENO[@]}]" >&2 
} 
export -f bar1

./foo
EOF
chmod +x bar

./ bar 的输出:

bar1 BEFORE: 3 main ./foo [bar1 main] [./foo] [3 0]
bar2 IN:  [bar2 bar1 main] [./foo] [1 3 0]
bar1 AFTER:  [bar1 main] [] [3 0]

如您所见,与导出的函数调用相对应的堆栈帧不会添加到 BASH_SOURCE 中,但是只要有函数返回,就会弹出最高堆栈帧。

As you can see, stack frames corresponding to invocations of exported functions aren't added to BASH_SOURCE, but whenever a function returns the topmost stack frame is popped.

请注意 FUNCNAME 变量不受此错误影响。因此,如果仅需要呼叫者的姓名,则可以将其作为 $ {FUNCNAME [1]} 获得。

Note that the FUNCNAME variable is not affected by this bug. Thus, if you need only the name of the caller you can obtain it as ${FUNCNAME[1]}.

这篇关于bash调用程序内建函数无法从导出的函数运行,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆