Як визначити ім'я функції зсередини функції


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 :

FUNCNAME

Змінна масиву, що містить імена всіх функцій оболонки, що знаходяться в стеці виклику виконання. Елемент з індексом 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]if, якщо це мається на увазі, отримуючи доступ до необмеженої змінної?
Том Хейл,

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.