fonction d'appel déclarée ci-dessous

15

Est-il possible d'appeler une fonction qui est déclarée ci-dessous en bash?

Exemple

if [ "$input" = "yes" ]; then
    YES_FUNCTION
elif [ "$input" = "no" ]; then
    NO_FUNCTION
else
    exit 0;
fi

YES_FUNCTION()
{
  .....
  .....
}

NO_FUNCTION()
{
  .....
  .....
}
msp9011
la source

Réponses:

36

Comme d'autres l'ont dit, vous ne pouvez pas faire ça.

Mais si vous souhaitez organiser le code dans un fichier afin que le programme principal soit en haut du fichier et que d'autres fonctions soient définies ci-dessous, vous pouvez le faire en ayant une mainfonction distincte .

Par exemple

#!/bin/sh

main() {
    if [ "$1" = yes ]; then
        do_task_this
    else
        do_task_that
    fi
}

do_task_this() {
    ...
} 
do_task_that() {
    ...
} 

main "$@"; exit

Lorsque nous appelons mainà la fin du fichier, toutes les fonctions sont déjà définies. Un passage explicite "$@"à mainest requis pour rendre les arguments de ligne de commande du script visibles dans la fonction.

L'explicite exitsur la même ligne que l'appel à main n'est pas obligatoire, mais peut être utilisé pour empêcher un script en cours d'exécution d'être gâché si le fichier de script est modifié. Sans cela, le shell essaierait de continuer à lire les commandes du fichier de script après les mainretours. (voir Comment lire l'intégralité du script shell avant de l'exécuter? )

ilkkachu
la source
@ikkachu pense que cela devrait fonctionner .. laissez-moi vérifier.
msp9011
7
Avec les scripts Bash, j'utilise souvent [[ ${BASH_SOURCE[0]} = "$0" ]] && Main "$@"pour appeler la fonction principale afin de pouvoir la source dans un autre script sans Mainêtre exécuté. Ensuite, je peux soit réutiliser les fonctions ou écrire des tests pour les vérifier.
BlackJack
11
Avoir main "$@"; exit(avec exitsur la même ligne que main) est également utile comme protection contre la modification du fichier pendant son interprétation.
Stéphane Chazelas
2
@JoL, ce qui est lu n'est pas lu à nouveau, et le shell devra lire et analyser tout le texte d'une boucle avant de commencer à l'exécuter, mais après le retour de la boucle, il continuera à lire à partir du reste du fichier à la position actuelle (et si le fichier a été modifié il va bousiller les choses). Si tout est dans des fonctions, le shell doit tout lire avant de commencer à faire quoi que ce soit (sauf définir ces fonctions), si nous mettons la exitsur la même ligne car mainnous nous assurons que le shell ne lira plus rien du fichier après les mainretours.
Stéphane Chazelas
1
@MontyHarder, peu importe si vous utilisez main; exit, main; exit $?ou main <EOF>, dans tous les cas, le code de sortie de mainest utilisé comme code de sortie du script. Ce exitserait juste pour empêcher les choses de se gâcher si quelqu'un modifie le script pendant qu'il est en cours d'exécution.
ilkkachu
13

Non, les fonctions doivent exister dans l'environnement shell au moment de leur appel.

Le "Shell Style Guide" de Google propose un correctif:

Une fonction appelée mainest requise pour les scripts suffisamment longs pour contenir au moins une autre fonction.

À la toute fin du script, après toutes les fonctions, comme la seule instruction qui ne se trouve pas dans une fonction, vous auriez

main "$@"

Cela appellerait la mainfonction avec tous les paramètres donnés au script. La mainfonction pourrait être située en haut du script (le guide de style dit de la mettre en bas, mais là encore, elle dit beaucoup de choses).

Lorsque le shell arrive à l' mainappel, toutes les fonctions du script ont été analysées et peuvent donc être appelées à partir de la mainfonction.

Kusalananda
la source
9

Non, les fonctions doivent être déclarées avant d'être utilisées. Les scripts shell sont lus ligne par ligne et agis ligne par ligne; donc une fonction n'existe pas tant que sa déclaration n'a pas été exécutée.

Stephen Kitt
la source
Vous avez raison. le problème est que j'ai plus de 30 fonctions dans un script. c'est assez délicat quand on lit le code. C'est Cconfortable.
msp9011
3
Vous pouvez placer vos déclarations de fonction dans un autre fichier et le source ( . yourfile).
Stephen Kitt
Oui, j'ai essayé, mais l'exigence est d'avoir un seul script.
msp9011
@SivaPrasath Quel est exactement le problème? Il suffit de définir toutes les fonctions, peut-être même de mettre le code principal dans une fonction, puis la dernière ligne indique quelle fonction est appelée et contient la partie principale du script.
BlackJack
@SivaPrasath En C, vous n'avez pas d' ifinstructions nues en dehors d'une fonction. La fonction n'a pas besoin d'être définie lorsque vous déclarez la iffonction -containing, juste lorsque vous l' appelez .
chepner
4

Le shell n'a pas de concept de declaringfonction. Vous ne pouvez donc pas avoir de déclaration à terme.

Par conséquent, vous devez faire lire l'implémentation de la fonction par le shell avant de pouvoir l'appeler.

schily
la source
4
Techniquement, certains shells (ksh, zsh) ont une fonction de chargement automatique de fonction qui pourrait être vue comme une forme de déclaration (où autoload fdéclare la fonction, mais son corps n'est chargé qu'au premier appel). Cela ne s'applique cependant pas aux PO bash.
Stéphane Chazelas