Dans la programmation impérative typique , vous écrivez des séquences d'instructions et elles sont exécutées les unes après les autres, avec un flux de contrôle explicite. Par exemple:
if [ -f file1 ]; then # If file1 exists ...
cp file1 file2 # ... create file2 as a copy of a file1
fi
etc.
Comme le montre l'exemple, dans la programmation impérative, vous suivez assez facilement le flux d'exécution, en remontant toujours à partir d'une ligne de code donnée pour déterminer son contexte d'exécution, sachant que toutes les instructions que vous donnerez seront exécutées à la suite de leur l'emplacement dans le flux (ou l'emplacement de leurs sites d'appel, si vous écrivez des fonctions).
Comment les rappels modifient le flux
Lorsque vous utilisez des rappels, au lieu de placer l'utilisation d'un ensemble d'instructions «géographiquement», vous décrivez quand il doit être appelé. Des exemples typiques dans d'autres environnements de programmation sont des cas tels que «téléchargez cette ressource, et lorsque le téléchargement est terminé, appelez ce rappel». Bash n'a pas de construction de rappel générique de ce type, mais il a des rappels, pour la gestion des erreurs et quelques autres situations; par exemple (il faut d'abord comprendre les modes de substitution de commandes et de sortie Bash pour comprendre cet exemple):
#!/bin/bash
scripttmp=$(mktemp -d) # Create a temporary directory (these will usually be created under /tmp or /var/tmp/)
cleanup() { # Declare a cleanup function
rm -rf "${scripttmp}" # ... which deletes the temporary directory we just created
}
trap cleanup EXIT # Ask Bash to call cleanup on exit
Si vous voulez essayer vous-même, enregistrez ce qui précède dans un fichier, par exemple cleanUpOnExit.sh
, rendez-le exécutable et exécutez-le:
chmod 755 cleanUpOnExit.sh
./cleanUpOnExit.sh
Mon code ici n'appelle jamais explicitement la cleanup
fonction; il indique à Bash quand l'appeler, en utilisant trap cleanup EXIT
, par exemple «cher Bash, veuillez exécuter la cleanup
commande lorsque vous quittez» (et cleanup
il se trouve que c'est une fonction que j'ai définie plus tôt, mais cela pourrait être tout ce que Bash comprend). Bash le prend en charge pour tous les signaux non fatals, les sorties, les échecs de commande et le débogage général (vous pouvez spécifier un rappel qui est exécuté avant chaque commande). Le rappel ici est la cleanup
fonction, qui est «rappelée» par Bash juste avant la sortie du shell.
Vous pouvez utiliser la capacité de Bash pour évaluer les paramètres du shell en tant que commandes, pour construire un framework orienté callback; c'est un peu au-delà de la portée de cette réponse, et provoquerait peut-être plus de confusion en suggérant que la transmission de fonctions implique toujours des rappels. Voir Bash: passer une fonction comme paramètre pour quelques exemples de la fonctionnalité sous-jacente. L'idée ici, comme pour les rappels de gestion d'événements, est que les fonctions peuvent prendre des données en tant que paramètres, mais aussi d'autres fonctions - cela permet aux appelants de fournir un comportement ainsi que des données. Un exemple simple de cette approche pourrait ressembler à
#!/bin/bash
doonall() {
command="$1"
shift
for arg; do
"${command}" "${arg}"
done
}
backup() {
mkdir -p ~/backup
cp "$1" ~/backup
}
doonall backup "$@"
(Je sais que c'est un peu inutile car cp
peut traiter plusieurs fichiers, c'est uniquement à titre d'illustration.)
Ici, nous créons une fonction, doonall
qui prend une autre commande, donnée en paramètre, et l'applique au reste de ses paramètres; nous utilisons ensuite cela pour appeler la backup
fonction sur tous les paramètres donnés au script. Le résultat est un script qui copie tous ses arguments, un par un, dans un répertoire de sauvegarde.
Ce type d'approche permet d'écrire des fonctions avec des responsabilités uniques: doonall
la responsabilité de est d'exécuter quelque chose sur tous ses arguments, un à la fois; backup
La responsabilité de est de faire une copie de son (unique) argument dans un répertoire de sauvegarde. Les deux doonall
et backup
peuvent être utilisés dans d'autres contextes, ce qui permet une plus grande réutilisation du code, de meilleurs tests, etc.
Dans ce cas, le rappel est la backup
fonction, que nous disons doonall
de «rappeler» sur chacun de ses autres arguments - nous fournissons le doonall
comportement (son premier argument) ainsi que les données (les arguments restants).
(Notez que dans le type de cas d'utilisation démontré dans le deuxième exemple, je n'utiliserais pas le terme «rappel» moi-même, mais c'est peut-être une habitude résultant des langages que j'utilise. Je pense que cela passe des fonctions ou des lambdas autour , plutôt que d'enregistrer des rappels dans un système orienté événement.)