Cómo determinar el nombre de la función desde dentro de una función

163

Si tengo un script Bash como:

#!/bin/bash

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

¿Hay alguna forma de hacer esto? Esto podría usarse en mensajes de ayuda como

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

Solo en este caso lo que quería no es $0, que es el nombre del archivo de la secuencia de comandos.

Yan
fuente
2
Relacionado: Marco de registro de Bash que usa una FUNCNAMEmatriz y otras variables de Bash: github.com/codeforester/base/blob/master/lib/stdlib.sh . Ver funciones log_debug_entery log_debug_leaveen particular.
codeforester

Respuestas:

236

Se puede utilizar ${FUNCNAME[0]}en bashconseguir el nombre de la función.

TheBonsai
fuente
79

Del Manual de referencia de Bash :

FUNCNAME

Una variable de matriz que contiene los nombres de todas las funciones de shell actualmente en la pila de llamadas de ejecución. El elemento con índice 0 es el nombre de cualquier función de shell que se esté ejecutando actualmente. El elemento más inferior (el que tiene el índice más alto) es "principal". Esta variable existe solo cuando se ejecuta una función de shell. Las asignaciones a FUNCNAME no tienen efecto y devuelven un estado de error. Si FUNCNAME no está configurado, pierde sus propiedades especiales, incluso si posteriormente se restablece.

Esta variable se puede usar con BASH_LINENO y BASH_SOURCE. Cada elemento de FUNCNAME tiene elementos correspondientes en BASH_LINENO y BASH_SOURCE para describir la pila de llamadas. Por ejemplo, $ {FUNCNAME [$ i]} fue llamado desde el archivo $ {BASH_SOURCE [$ i + 1]} en el número de línea $ {BASH_LINENO [$ i]}. La persona que llama muestra la pila de llamadas actual con esta información.

Cuando se accede a las matrices bash sin un índice, se devolverá el primer elemento de la matriz, por $FUNCNAMElo que funcionará en casos simples para proporcionar el nombre de la función inmediatamente actual, pero también contiene todas las demás funciones en la pila de llamadas. Por ejemplo:

# 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

Saldrá:

$ bash foobar
In function foo: FUNCNAME=foo foobar main
foobar
In function foobar: FUNCNAME=foobar main
bschlueter
fuente
66
Aún no lo entiendo. ¿Por qué agregar el [0]si está implícito al acceder a la variable no decorada?
Tom Hale
15
¿Porque es engañoso e ignorante del tipo real de la variable? Claro, no siempre es necesario, pero como muchos otros bash-isms, es una convención perezosa. Es mejor ser explícito que ambiguo.
bschlueter
36

Yo uso ${FUNCNAME[0]}para imprimir el nombre de la función actual

Verdigrass
fuente
@bschlueter pero cuando hace referencia a una matriz sin tratarla como una matriz en Bash, solo imprime el primer valor; por lo tanto, ¿cómo es incorrecta la respuesta aceptada?
Alexej Magura el
44
Claro, y eso es conveniente, pero terrible para el mantenimiento y las pruebas. No seas perezoso, sé explícito.
bschlueter
1

Otro ejemplo:

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

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

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

Saldrá:

begin main
foo fuction begins
foobar fuction begins
end main
Mickey White
fuente
-1

La forma más simple de obtener el nombre de la función (desde dentro de una función)

echo $0
jasonleonhard
fuente
Por favor, deja de abusar ###de tus respuestas.
Marcin Orlowski
@MarcinOrlowski ¿Estás bien? Parece que podrías usar un abrazo.
jasonleonhard