Comment déterminer le nom de la fonction depuis l'intérieur d'une fonction

163

Si j'ai un script Bash comme:

#!/bin/bash

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

Y a-t-il un moyen de faire ça? Cela pourrait être utilisé dans les messages d'aide tels que

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

Ce n'est que dans ce cas que ce que je voulais $0, ce n'est pas le nom de fichier du script.

Yan
la source
2
Connexes: Framework de journalisation Bash qui utilise un FUNCNAMEtableau et d'autres variables Bash: github.com/codeforester/base/blob/master/lib/stdlib.sh . Voir les fonctions log_debug_enteret log_debug_leaveen particulier.
codeforester

Réponses:

236

Vous pouvez utiliser ${FUNCNAME[0]}in bashpour obtenir le nom de la fonction.

TheBonsai
la source
79

À partir du manuel de référence Bash :

FUNCNAME

Une variable de tableau contenant les noms de toutes les fonctions du shell actuellement dans la pile des appels d'exécution. L'élément d'index 0 est le nom de toute fonction shell en cours d'exécution. L'élément le plus bas (celui avec l'indice le plus élevé) est "main". Cette variable n'existe que lorsqu'une fonction shell est en cours d'exécution. Les affectations à FUNCNAME n'ont aucun effet et renvoient un état d'erreur. Si FUNCNAME n'est pas défini, il perd ses propriétés spéciales, même s'il est réinitialisé ultérieurement.

Cette variable peut être utilisée avec BASH_LINENO et BASH_SOURCE. Chaque élément de FUNCNAME a des éléments correspondants dans BASH_LINENO et BASH_SOURCE pour décrire la pile d'appels. Par exemple, $ {FUNCNAME [$ i]} a été appelé à partir du fichier $ {BASH_SOURCE [$ i + 1]} à la ligne numéro $ {BASH_LINENO [$ i]}. L'appelant intégré affiche la pile d'appels actuelle à l'aide de ces informations.

Lorsque les tableaux bash sont accédés sans index, le premier élément du tableau sera retourné, donc $FUNCNAMEfonctionnera dans des cas simples pour fournir le nom de la fonction immédiatement courante, mais il contient également toutes les autres fonctions de la pile d'appels. Par exemple:

# 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

Sortira:

$ bash foobar
In function foo: FUNCNAME=foo foobar main
foobar
In function foobar: FUNCNAME=foobar main
bschlueter
la source
6
Je ne comprends toujours pas. Pourquoi ajouter le [0]si c'est implicite en accédant à la variable non décorée?
Tom Hale
15
Parce qu'il est trompeur et ignorant le type réel de la variable? Bien sûr, ce n'est pas toujours nécessaire, mais comme beaucoup d'autres bash-ismes, c'est une convention paresseuse. Mieux vaut être explicite qu'ambigu.
bschlueter
36

J'utilise ${FUNCNAME[0]}pour imprimer le nom de la fonction actuelle

Verdigrass
la source
@bschlueter mais lorsque vous référencez un tableau sans le traiter comme un tableau dans Bash, il imprime simplement la première valeur; par conséquent, comment la réponse acceptée est-elle incorrecte?
Alexej Magura
4
Bien sûr, et c'est pratique, mais terrible pour la maintenance et les tests. Ne soyez pas paresseux, soyez explicite.
bschlueter
1

Un autre exemple:

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

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

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

Sortira:

begin main
foo fuction begins
foobar fuction begins
end main
Mickey blanc
la source
-1

Le moyen le plus simple d'obtenir le nom de la fonction (depuis l'intérieur d'une fonction)

echo $0
Jasonleonhard
la source
Veuillez arrêter d'abuser ###dans vos réponses.
Marcin Orlowski
@MarcinOrlowski Est-ce que ça va? On dirait que vous pourriez utiliser un câlin.
jasonleonhard