bash调用者内置函数从导出的函数停止工作,为什么?

时间:2016-06-21 18:47:43

标签: bash introspection built-in

我使用UPDATE `Master_table` SET `first` = (SELECT `first` FROM `table_1`) WHERE `id` IN(SELECT `id` FROM `table_1`); 和导出函数给出了一个非常奇怪的问题,以便为内置bash的调用提供可靠的答案。

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

然后,只有在bar1的通话后,来电内置才会打破。这是正常的吗?你能解释一下原因吗?你可以简化以下代码来解决这个问题吗?

非常清楚,以下是如何在您的系统上重现:构建两个文件:

bar1

然后你可以摆弄并看到:

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: 

最终,我的问题是:如何在所有情况下绕过这个问题并获得来电者

附加信息:

    来自ubuntu软件包$ ./bar bar1 BEFORE: 9 main ./foo bar2 IN: 5 bar ./foo bar1 AFTER: 9 main ./foo
  • bash版本:4.3.42(1)-release (x86_64-pc-linux-gnu)

1 个答案:

答案 0 :(得分:3)

这是bash中的bug。它已在4.4版中修复。

存在导出的函数时,BASH_SOURCE变量未正确维护。您可以通过显示FUNCNAMEBASH_SOURCEBASH_LINENO特殊变量的内容来检查它:

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,但只要函数返回,就会弹出最顶层的堆栈帧。

请注意,FUNCNAME变量不受此错误的影响。因此,如果您只需要调用者的名称,则可以将其作为${FUNCNAME[1]}获取。