Как определить имя функции изнутри функции


163

Если у меня есть скрипт Bash вроде:

#!/bin/bash

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

Есть какой-либо способ сделать это? Это может быть использовано в справочных сообщениях, таких как

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

Только в этом случае мне не нужно то $0, что является именем файла скрипта.


2
Связанный: Структура ведения журнала Bash, использующая FUNCNAMEмассив и другие переменные Bash: github.com/codeforester/base/blob/master/lib/stdlib.sh . Смотрите функции log_debug_enterи log_debug_leaveв частности.
Codeforester

Ответы:


236

Вы можете использовать ${FUNCNAME[0]}в , bashчтобы получить имя функции.


79

Из справочного руководства Bash :

имя_функции

Переменная массива, содержащая имена всех функций оболочки, находящихся в данный момент в стеке вызовов выполнения. Элемент с индексом 0 является именем любой выполняемой в данный момент функции оболочки. Самый нижний элемент (с самым высоким индексом) является «основным». Эта переменная существует только при выполнении функции оболочки. Назначения FUNCNAME не имеют никакого эффекта и возвращают статус ошибки. Если FUNCNAME не установлено, оно теряет свои специальные свойства, даже если оно впоследствии сбрасывается.

Эта переменная может использоваться с BASH_LINENO и BASH_SOURCE. Каждый элемент FUNCNAME имеет соответствующие элементы в BASH_LINENO и BASH_SOURCE для описания стека вызовов. Например, $ {FUNCNAME [$ i]} был вызван из файла $ {BASH_SOURCE [$ i + 1]} по номеру строки $ {BASH_LINENO [$ 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
Потому что он обманчив и не знает фактического типа переменной? Конечно, это не всегда необходимо, но, как и во многих других случаях, это ленивое соглашение. Лучше быть явным, чем двусмысленным.
bschlueter

36

Я использую, ${FUNCNAME[0]}чтобы напечатать текущее имя функции


@bschlueter, но когда вы ссылаетесь на массив, не рассматривая его как массив в Bash, он просто печатает первое значение; следовательно, как принятый ответ неверен?
Алексей Магура

4
Конечно, и это удобно, но ужасно для обслуживания и тестирования. Не ленись, будь откровенен.
bschlueter

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.