Jak określić nazwę funkcji z wnętrza funkcji

163

Jeśli mam skrypt Bash taki jak:

#!/bin/bash

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

Czy jest na to sposób? Można to wykorzystać w wiadomościach pomocy, takich jak

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

Tylko w tym przypadku nie chciałem $0, czyli nazwa pliku skryptu.

Yan
źródło
2
Powiązane: Struktura rejestrowania Bash, która wykorzystuje FUNCNAMEtablicę i inne zmienne Bash: github.com/codeforester/base/blob/master/lib/stdlib.sh . Zobacz funkcje log_debug_enteri log_debug_leavew szczególności.
codeforester

Odpowiedzi:

236

Możesz użyć ${FUNCNAME[0]}in, bashaby uzyskać nazwę funkcji.

TheBonsai
źródło
79

Z podręcznika Bash :

FUNCNAME

Zmienna tablicowa zawierająca nazwy wszystkich funkcji powłoki aktualnie znajdujących się na stosie wywołań wykonania. Element o indeksie 0 to nazwa aktualnie wykonywanej funkcji powłoki. Najniższy element (ten o najwyższym indeksie) to „główny”. Ta zmienna istnieje tylko wtedy, gdy wykonywana jest funkcja powłoki. Przypisania do FUNCNAME nie mają żadnego efektu i zwracają stan błędu. Jeśli funkcja FUNCNAME nie jest ustawiona, traci swoje specjalne właściwości, nawet jeśli zostanie później zresetowana.

Ta zmienna może być używana z BASH_LINENO i BASH_SOURCE. Każdy element FUNCNAME ma odpowiadające sobie elementy w BASH_LINENO i BASH_SOURCE, które opisują stos wywołań. Na przykład $ {FUNCNAME [$ i]} została wywołana z pliku $ {BASH_SOURCE [$ i + 1]} w wierszu o numerze $ {BASH_LINENO [$ i]}. Wbudowane urządzenie wywołujące wyświetla bieżący stos wywołań przy użyciu tych informacji.

Kiedy dostęp do tablic bash jest wykonywany bez indeksu, zostanie zwrócony pierwszy element tablicy, więc $FUNCNAMEw prostych przypadkach będzie działać, aby podać nazwę natychmiast bieżącej funkcji, ale zawiera ona również wszystkie inne funkcje na stosie wywołań. Na przykład:

# 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

Wyświetli:

$ bash foobar
In function foo: FUNCNAME=foo foobar main
foobar
In function foobar: FUNCNAME=foobar main
bschlueter
źródło
6
Nadal nie rozumiem. Po co dodawać, [0]jeśli jest to dorozumiane, uzyskując dostęp do niezdekorowanej zmiennej?
Tom Hale
15
Ponieważ jest zwodniczy i nie zna rzeczywistego typu zmiennej? Jasne, nie zawsze jest to konieczne, ale podobnie jak wiele innych bashizmów jest to leniwa konwencja. Lepiej być wyraźnym niż niejednoznacznym.
bschlueter
36

Używam ${FUNCNAME[0]}do wypisania aktualnej nazwy funkcji

Verdigrass
źródło
@bschlueter, ale kiedy odwołujesz się do tablicy bez traktowania jej jak tablicy w Bash, po prostu wypisuje pierwszą wartość; zatem dlaczego przyjęta odpowiedź jest nieprawidłowa?
Alexej Magura
4
Jasne i jest to wygodne, ale straszne w przypadku konserwacji i testowania. Nie bądź leniwy, bądź bezpośredni.
bschlueter
1

Inny przykład:

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

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

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

Wyświetli:

begin main
foo fuction begins
foobar fuction begins
end main
Mickey White
źródło
-1

Najprostszy sposób na uzyskanie nazwy funkcji (z wnętrza funkcji)

echo $0
jasonleonhard
źródło
Przestań nadużywać ###swoich odpowiedzi.
Marcin Orłowski
@MarcinOrlowski Wszystko w porządku? Wygląda na to, że przydałby się uścisk.
jasonleonhard