Transférer les déclarations de fonction dans un script Bash ou Shell?

95

Existe-t-il une telle chose bashou au moins quelque chose de similaire (contournement) comme les déclarations avancées, bien connues en C / C ++, par exemple?

Ou il y en a tellement parce que, par exemple, il est toujours exécuté en une seule passe (ligne après ligne)?

S'il n'y a pas de déclarations avant, que dois-je faire pour rendre mon script plus facile à lire. C'est plutôt long et ces définitions de fonction au début, mélangées à des variables globales, donnent à mon script un aspect moche et difficile à lire / comprendre)? Je demande à apprendre quelques bonnes pratiques bien connues pour de tels cas.


Par exemple:

# something like forward declaration
function func

# execution of the function
func

# definition of func
function func
{
    echo 123
}
Kiril Kirov
la source

Réponses:

190

Excellente question. J'utilise un modèle comme celui-ci pour la plupart de mes scripts:

#!/bin/bash

main() {
    foo
    bar
    baz
}

foo() {
}

bar() {
}

baz() {
}

main "$@"

Vous pouvez lire le code de haut en bas, mais il ne commence réellement à s'exécuter qu'à la dernière ligne. En passant "$@"à main () , vous pouvez accéder aux arguments de ligne de commande $1, $2et al comme vous le feriez normalement.

John Kugelman
la source
3
Salut, comment structurez-vous les données qui doivent être partagées entre foo / bar / baz dans votre exemple? Habituellement, je le mets simplement en haut du script. Est-ce toujours le cas lors de l'utilisation des fonctions? Ou est-il préférable de placer les données globales dans main, puis de les transmettre à foo / bar / baz comme arguments? Quelle est la meilleure pratique?
bodacydo
4
Je préfère les arguments. Sauf cela, je définirai des variables globales dans mainou dans une fonction juste après main(par exemple, setupou parseArguments). J'évite d'avoir des variables globales définies ci main- dessus - le code ne doit pas sortir de main.
John Kugelman
Cela semble quelque peu analogue à ce qui se if _ _ name _ _ == "_ _ main _ _": main()passe en python
Sergiy Kolodyazhnyy
C'est également fantastique lorsque vous utilisez des outils comme Bats pour tester vos scripts, décomposer le tout en fonctions rend le test des composants individuels beaucoup plus facile. Voir aussi l' article de blog
dragon788
30

Lorsque mes scripts bash se développent trop, j'utilise un mécanisme d'inclusion:

Fichier allMyFunctions:

foo() {
}

bar() {
}

baz() {
}

Fichier main:

#!/bin/bash

. allMyfunctions

foo
bar
baz
mouviciel
la source
27
Personnellement, lorsqu'un script shell commence à dépasser un fichier, j'ai tendance à passer à une autre langue ;-)
Joachim Sauer
Ne serait-il pas préférable d'utiliser source allMyfunctions?
pydoge
4
@pydoge: sourcen'est pas compatible POSIX. bashdéfinit sourcecomme un alias de .: ils sont fonctionnellement équivalents.
mouviciel