J'ai besoin de passer une fonction en paramètre dans Bash. Par exemple, le code suivant:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
Devrait afficher:
before
Hello world
after
Je sais que ce eval
n'est pas correct dans ce contexte, mais ce n'est qu'un exemple :)
Une idée?
function
mot, vous ne pouvez pas accéder à ces méthodes internes tant que vous n'avez pas exécuté la méthode de niveau supérieur.Je ne pense pas que quiconque ait tout à fait répondu à la question. Il n'a pas demandé s'il pouvait faire écho aux chaînes dans l'ordre. Au contraire, l'auteur de la question veut savoir s'il peut simuler le comportement du pointeur de fonction.
Il y a quelques réponses qui ressemblent beaucoup à ce que je ferais, et je veux les développer avec un autre exemple.
De l'auteur:
function x() { echo "Hello world" } function around() { echo "before" ($1) <------ Only change echo "after" } around x
Pour développer cela, nous aurons la fonction x echo "Hello world: $ 1" pour montrer quand l'exécution de la fonction se produit réellement. Nous allons passer une chaîne qui est le nom de la fonction "x":
function x() { echo "Hello world:$1" } function around() { echo "before" ($1 HERE) <------ Only change echo "after" } around x
Pour décrire cela, la chaîne "x" est passée à la fonction around () qui fait écho "before", appelle la fonction x (via la variable $ 1, le premier paramètre passé à around) en passant l'argument "HERE", enfin écho après .
En outre, c'est la méthodologie pour utiliser des variables comme noms de fonction. Les variables contiennent en fait la chaîne qui est le nom de la fonction et ($ variable arg1 arg2 ...) appelle la fonction en passant les arguments. Voir ci-dessous:
function x(){ echo $3 $1 $2 <== just rearrange the order of passed params } Z="x" # or just Z=x ($Z 10 20 30)
donne: 30 10 20, où nous avons exécuté la fonction nommée "x" stockée dans la variable Z et passé les paramètres 10 20 et 30.
Ci-dessus où nous référençons les fonctions en attribuant des noms de variables aux fonctions afin que nous puissions utiliser la variable au lieu de connaître réellement le nom de la fonction (ce qui est similaire à ce que vous pourriez faire dans une situation de pointeur de fonction très classique en c pour généraliser le flux du programme mais pré -sélectionner les appels de fonction que vous allez effectuer en fonction des arguments de la ligne de commande).
Dans bash, ce ne sont pas des pointeurs de fonction, mais des variables qui font référence à des noms de fonctions que vous utiliserez plus tard.
la source
()
ne démarre-t- il pas un sous-shell?il n'y a pas besoin d'utiliser
eval
function x() { echo "Hello world" } function around() { echo "before" var=$($1) echo "after $var" } around x
la source
Vous ne pouvez rien transmettre à une fonction autre que des chaînes. Les substitutions de processus peuvent en quelque sorte faire semblant. Bash a tendance à maintenir le FIFO ouvert jusqu'à ce qu'une commande soit étendue pour se terminer.
Voici un rapide idiot
foldl() { echo $(($(</dev/stdin)$2)) } < <(tr '\n' "$1" <$3) # Sum 20 random ints from 0-999 foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)
Les fonctions peuvent être exportées, mais ce n'est pas aussi intéressant qu'il n'y paraît. Je trouve que c'est principalement utile pour rendre les fonctions de débogage accessibles aux scripts ou à d'autres programmes qui exécutent des scripts.
( id() { "$@" } export -f id exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi' )
id
obtient toujours uniquement une chaîne qui se trouve être le nom d'une fonction (importée automatiquement à partir d'une sérialisation dans l'environnement) et ses arguments.Le commentaire de Pumbaa80 à une autre réponse est également bon (
eval $(declare -F "$1")
), mais il est principalement utile pour les tableaux, pas pour les fonctions, car ils sont toujours globaux. Si vous l'exécutiez dans une fonction, tout ce qu'il ferait serait de la redéfinir, donc il n'y a aucun effet. Il ne peut pas être utilisé pour créer des fermetures ou des fonctions partielles ou des "instances de fonction" dépendant de ce qui se trouve être lié dans la portée actuelle. Au mieux, cela peut être utilisé pour stocker une définition de fonction dans une chaîne qui est redéfinie ailleurs - mais ces fonctions ne peuvent également être codées en dur que si bien sûreval
est utiliséFondamentalement, Bash ne peut pas être utilisé comme ça.
la source
Une meilleure approche consiste à utiliser des variables locales dans vos fonctions. Le problème est alors de savoir comment obtenir le résultat pour l'appelant. Un mécanisme consiste à utiliser la substitution de commande:
function myfunc() { local myresult='some value' echo "$myresult" } result=$(myfunc) # or result=`myfunc` echo $result
Ici, le résultat est sorti vers la sortie standard et l'appelant utilise la substitution de commande pour capturer la valeur dans une variable. La variable peut ensuite être utilisée selon les besoins.
la source
Vous devriez avoir quelque chose du genre:
function around() { echo 'before'; echo `$1`; echo 'after'; }
Vous pouvez alors appeler
around x
la source
eval est probablement le seul moyen d'y parvenir. Le seul vrai inconvénient est l'aspect sécurité, car vous devez vous assurer que rien de malveillant n'est transmis et que seules les fonctions que vous voulez être appelées seront appelées (en plus de vérifier qu'il n'y a pas de mauvais caractères comme ';' dedans aussi).
Donc, si c'est vous qui appelez le code, alors eval est probablement le seul moyen de le faire. Notez qu'il existe d'autres formes d'évaluation qui fonctionneraient probablement aussi avec des sous-commandes ($ () et ``), mais elles ne sont pas plus sûres et sont plus chères.
la source
eval $1
souhaitez appeler une fonction en utilisantif declare -F "$1" >/dev/null; then eval $1; fi
eval $(declare -F "$1")