如何从函数内部确定函数名称


163

如果我有一个Bash脚本,例如:

#!/bin/bash

f() {
  # echo function name, "f" in this case
}

有什么办法吗?这可以用于帮助消息中,例如

printf "Usage: %s: blah blah blah \n" $(basename $0) >&2; 

仅在这种情况下,我想要的不是$0,这是脚本的文件名。


2
相关:使用FUNCNAME数组和其他Bash变量的Bash日志记录框架:github.com/codeforester/base/blob/master/lib/stdlib.sh。请参阅功能log_debug_enterlog_debug_leave特别。
codeforester

Answers:


236

您可以使用${FUNCNAME[0]}in bash获得函数名称。


79

Bash参考手册

功能名称

一个数组变量,包含当前在执行调用堆栈中的所有shell函数的名称。索引为0的元素是任何当前正在执行的Shell函数的名称。最底部的元素(具有最高索引的元素)是“ main”。该变量仅在执行Shell函数时存在。分配给FUNCNAME无效,并返回错误状态。如果未设置FUNCNAME,则即使随后将其重置,它也会丢失其特殊属性。

此变量可以与BASH_LINENO和BASH_SOURCE一起使用。FUNCNAME的每个元素在BASH_LINENO和BASH_SOURCE中都有相应的元素来描述调用堆栈。例如,从文件$ {BASH_SOURCE [$ i + 1]}在行号$ {BASH_LINENO [$ i]}处调用了$ {FUNCNAME [$ i]}。内置呼叫方使用此信息显示当前呼叫堆栈。

当不带索引访问bash数组时,将返回该数组的第一个元素,因此$FUNCNAME在简单情况下可以提供当前当前函数的名称,但它也包含调用堆栈中的所有其他函数。例如:

# in a file "foobar"
function foo {
    echo foo
    echo "In function $FUNCNAME: FUNCNAME=${FUNCNAME[*]}" >&2
}

function foobar {
    echo "$(foo)bar"
    echo "In function $FUNCNAME: FUNCNAME=${FUNCNAME[*]}" >&2
}

foobar

将输出:

$ bash foobar
In function foo: FUNCNAME=foo foobar main
foobar
In function foobar: FUNCNAME=foobar main

6
我还是不明白。[0]如果通过访问未修饰的变量隐式添加,为什么还要添加?
汤姆·黑尔

15
因为它对变量的实际类型具有欺骗性和无知性?当然,这并不总是必需的,但是像许多其他bash-ism一样,这是一个懒惰的约定。明确而不是模棱两可。
bschlueter '16

36

${FUNCNAME[0]}用来打印当前函数名称


@bschlueter,但是当您引用一个数组而不将其视为Bash中的数组时,它只会打印第一个值;因此,接受的答案如何不正确?
Alexej Magura

4
当然,这很方便,但是对于维护和测试却很糟糕。不要偷懒,要明确。
bschlueter '16

1

另一个例子:

# in a file "foobar"
foo() {
    echo "$FUNCNAME fuction begins"
}

foobar() {
    echo "$FUNCNAME fuction begins"
}

echo 'begin main'
foo
foobar
echo 'end main'

将输出:

begin main
foo fuction begins
foobar fuction begins
end main

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.