bash caller builtin 停止从导出函数工作,为什么?
bash caller builtin stops working from exported function, why?
我在使用 bash
和导出函数时遇到非常奇怪的问题,以便为我提供对内置函数 caller
调用的可靠答案。
这是我的设置来说明这个问题:Bash 脚本 bar
定义并导出函数 bar1
和 bar2
。 bar2
呼叫 bar1
。 Bash 脚本 bar
然后执行 bash 脚本 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
然后您可以 fiddle 并查看:
$ ./bar
bar1 BEFORE: 3 main ./foo
bar2 IN:
bar1 AFTER:
我预计(行号有可接受的变化):
$ ./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)
来自 ubuntu 包 4.3-14ubuntu1
.
这是 bash 中的 bug。它已在 4.4 版中修复。
在存在导出函数的情况下,BASH_SOURCE
变量未正确维护。您可以通过显示 FUNCNAME
、BASH_SOURCE
、BASH_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
,但每当函数 returns 弹出最顶层堆栈帧时。
请注意,FUNCNAME
变量不受此错误影响。因此,如果您只需要来电者的姓名,您可以获得 ${FUNCNAME[1]}
.
我在使用 bash
和导出函数时遇到非常奇怪的问题,以便为我提供对内置函数 caller
调用的可靠答案。
这是我的设置来说明这个问题:Bash 脚本 bar
定义并导出函数 bar1
和 bar2
。 bar2
呼叫 bar1
。 Bash 脚本 bar
然后执行 bash 脚本 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
然后您可以 fiddle 并查看:
$ ./bar
bar1 BEFORE: 3 main ./foo
bar2 IN:
bar1 AFTER:
我预计(行号有可接受的变化):
$ ./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)
来自 ubuntu 包4.3-14ubuntu1
.
这是 bash 中的 bug。它已在 4.4 版中修复。
在存在导出函数的情况下,BASH_SOURCE
变量未正确维护。您可以通过显示 FUNCNAME
、BASH_SOURCE
、BASH_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
,但每当函数 returns 弹出最顶层堆栈帧时。
请注意,FUNCNAME
变量不受此错误影响。因此,如果您只需要来电者的姓名,您可以获得 ${FUNCNAME[1]}
.