Comment faire une boucle, c’est-à-dire concevoir un programme pour effectuer un travail répétitif à votre place
La boucle est l’une des constructions les plus fondamentales et les plus puissantes en informatique, car elle nous permet de répéter un ensemble de commandes, autant de fois que nous le voulons, sur une liste d’éléments de notre choix. Une grande partie de la pensée informatique implique de prendre une tâche et de la résoudre d’une manière qui peut être appliquée à plusieurs reprises à toutes les autres tâches similaires, et la boucle for est la façon dont nous faisons en sorte que l’ordinateur fasse ce travail répétitif:
Contrairement à la plupart du code que nous avons écrit jusqu’à présent à l’invite interactive, une boucle for ne s’exécute pas dès que nous appuyons sur Entrée:
Nous pouvons écrire autant de commandes que nous le souhaitons dans le bloc entre les mots clés do
et done
:
Seulement jusqu’à ce que nous atteignions done
et que nous appuyions sur Entrée, la boucle for fera son travail.
Ceci est fondamentalement différent de la commande et de la réponse ligne par ligne que nous avons expérimentée jusqu’à présent à l’invite. Et cela présage comment nous allons programmer plus loin: moins d’emphase sur l’exécution de commandes avec chaque ligne, et plus d’emphase sur la planification de la fonctionnalité d’un programme, puis son exécution plus tard.
Syntaxe de base
La syntaxe des boucles for
peut prêter à confusion, voici donc quelques exemples de base pour préparer / rafraîchir votre compréhension de celles-ci:
Voici « une version plus élaborée utilisant des variables:
Une substitution de commande peut être utilisée pour générer les éléments parcourus par la boucle for
:
Si vous avez besoin de lire une liste de lignes à partir d’un et soyez absolument sûr qu’aucune des lignes ne contient d’espace:
Une boucle de lecture en cours est une variante de ce qui précède, mais est plus sûr pour la lecture des lignes d’un fichier:
Construire une boucle for basique
Commençons par le début, avec un très minimale for
, puis l’a intégrée dans quelque chose de plus élaboré, pour nous aider à comprendre leur objectif.
La boucle la plus simple
C’est à peu près aussi simple comme vous pouvez faire une boucle for:
Cela vous a-t-il semblé assez inutile? Oui, ça aurait dû. J’ai écrit quatre lignes de code pour faire ce qu’il faut en une seule ligne, echo "Hi"
.
Plus d’éléments dans la collection
Il « C’est difficile à dire, mais une » boucle « s’est exécutée. Elle ne s’est exécutée qu’une seule fois. OK, alors comment faire pour qu’elle s’exécute plus d’une fois? Ajouter d’autres éléments (séparés par des espaces) à droite de in
mot-clé. Ajoutons quatre 1
« s:
OK, pas très excitant, mais le programme semblait au moins boucler: quatre 1
« s ont abouti à l’exécution de quatre commandes echo
.
Que se passe-t-il lorsque nous remplaçons ces quatre 1
« s par des nombres différents? Et peut-être quelques mots?
Et… rien. Donc la boucle ne fait rien de spécifique à la collection de valeurs que nous lui avons donnée. Pas encore en tout cas.
Reportez-vous à la variable de boucle
Regardons à gauche du mot-clé in
, et à cela x
. Quel est l’intérêt de ce x
? Un x
minuscule n’est pas le nom d’un mot-clé ou d’une commande que nous « avons rencontré jusqu’à présent (et l’exécuter seul à l’invite générera une erreur). Alors peut-être que c’est une variable? Essayons de la référencer dans l’instruction echo
:
Bingo. C’est à peu près le fonctionnement fondamental d’une boucle for
: – Obtenez une collection d’éléments / valeurs (Q Zebra 999 Smithsonian
) – Passez-les dans un for
Construction de boucle – En utilisant la variable de boucle (x
) comme espace réservé, écrivez des commandes entre les do
/ done
block – Lorsque la boucle s’exécute, la variable de boucle, x
, prend la valeur de chacun des éléments dans la liste – Q
, Zebra
, 999
, Smithsonian
, – et le bloc de commandes entre do
et done
est alors exécuté. Cette séquence se répète une fois pour chaque élément de la liste.
Le bloc do
/ done
peut contenir n’importe quelle séquence de commandes, même une autre for
-loop:
Loops-within-loops est une construction courante en programmation.Pour la plupart, je vais essayer d’éviter d’attribuer des problèmes qui impliqueraient ce type de logique, car il peut être difficile de détordre pendant le débogage.
Lire un fichier, ligne par ligne, de manière fiable avec lecture en cours
Puisque cat
imprime un fichier ligne par ligne, la boucle for suivante semble judicieuse:
Cependant, la substitution de commande obligera cat
à séparer les mots par espace. Si list-of-dirs.txt
contient le suivant:
La sortie de la boucle for
sera la suivante:
Une boucle de lecture tout en conservant les mots dans une ligne:
Nous pouvons également canaliser à partir du résultat d’une commande en la plaçant dans <(
et )
:
Pipes et boucles
Si vous venez d’autres langues, les flux de données ne vous sont peut-être pas familiers . Au moins, ils le sont pour moi, car la syntaxe pour travailler avec eux est beaucoup plus directe et directe dans Bash que dans Ruby ou Python.
Cependant, si vous « êtes nouveau dans la programmation dans n’importe quel langage, qu’est-ce qui pourrait on ne sait pas non plus en quoi travailler avec des flux de données est différent de travailler avec des boucles.
Par exemple, l’extrait suivant:
– produit le même résultat que cette boucle:
Et selon votre modèle mental des choses, il semble que dans les deux exemples, chaque mot, par exemple hello
, world
, est passé par un processus de traduction (via tr
) puis renvoyé en écho.
Tubes et filtres
Sans entrer dans les principes fondamentaux du système Unix, dans lequel un tube fonctionne fondamentalement différemment d’une boucle ici, laissez-moi suggérer une solution mentale:
Les programmes qui canalisent depuis stdin et stdout peuvent généralement être organisés sous forme de filtres, dans lesquels un flux de données entre dans un programme, et sort dans un format différent:
Pour les tâches qui ne consistent pas seulement à transformer des données, de filtre en filtre, pensez à utiliser une boucle. Qu’est-ce qu’une telle tâche pourrait être? À partir d’une liste d’URL, téléchargez chacune d’elles et envoyez par e-mail les données téléchargées, avec un corps et un objet personnalisés:
La source d’entrée des données, chaque URL dans urls.txt
, n’est pas vraiment filtré ici. Au lieu de cela, une tâche en plusieurs étapes est effectuée pour chaque URL.
Piping en lecture en cours
Cela dit, une boucle elle-même peut être implémentée comme un filtre de plus parmi les filtres. Prenez cette variante de la boucle de lecture en tout, dans laquelle le résultat de echo | grep
est redirigé, ligne par ligne, dans le while
, qui s’imprime sur stdout en utilisant echo
, qui est redirigé vers le fichier nommé some.txt:
Ce n’est pas une construction que vous devrez peut-être faire souvent, voire pas du tout, mais j’espère qu’elle renforce l’utilisation du tube sous Unix.
Programmation moins interactive
Le l’utilisation fréquente de boucles for
, et de constructions similaires, signifie que nous « repassons le bon vieux temps » de taper sur une ligne de c ommands et l’exécuter juste après avoir appuyé sur Entrée. Quel que soit le nombre de commandes que nous regroupons dans une boucle for
, rien ne se passe tant que nous n’avons pas atteint le mot-clé done
.
Écrivez une fois. Puis bouclez-le
Avec cette perte d’interaction ligne par ligne avec le shell, nous perdons le principal avantage de l’invite interactive: une rétroaction immédiate. Et nous avons encore tous les inconvénients: si nous faisons une faute de frappe plus tôt dans le bloc de commandes entre do
et done
, il faut commencer partout.
Voici donc comment nous atténuons cela:
Testez votre code, un cas à la fois
L’une des plus grandes erreurs que les novices font avec for
boucles est-ce qu’ils pensent qu’une boucle for
résout immédiatement leur problème. Donc, si ce qu’ils doivent faire, c’est télécharger 10 000 URL, mais ils ne peuvent pas télécharger correctement une seule URL, ils pensent que mettre leurs commandes défectueuses dans une boucle for
est un pas dans la bonne direction.
En plus de cela, c’est fondamentalement malentendu sur une boucle for
, le problème pratique est que vous exécutez maintenant votre code cassé 10 000 fois, ce qui signifie que vous devez attendre 10 000 fois plus longtemps pour découvrir que votre code est, hélas, toujours cassé.
Alors faites comme si vous n’aviez jamais entendu parler de for
boucles. Imaginez que vous devez télécharger les 10 000 URL, une commande à la fois. Pouvez-vous écrire la commande pour le faire pour la première URL. Et la seconde? Une fois que vous êtes raisonnablement sûr qu’aucune erreur de syntaxe mineure ne vous dérange, il est temps de réfléchir à la manière de trouver un modèle général pour les 9 997 autres URL.
Ecrire des scripts
La ligne de commande interactive est géniale.C’était amusant de commencer, et ce sera amusant tout au long de votre carrière informatique. Mais lorsque vous avez une grosse tâche devant vous, impliquant plus de dix lignes de code, alors il est temps de mettre ce code dans un script shell. Ne faites pas confiance à vos doigts humains faillibles pour retaper parfaitement le code.
Utilisez nano pour travailler sur des boucles et les enregistrer en tant que shell scripts. Pour les fichiers plus longs, je travaillerai sur l’éditeur de texte de mon ordinateur (Sublime Text), puis je les téléchargerai sur le serveur.
Exercice avec le web scraping
Juste pour ancrer le syntaxe et fonctionnement de la boucle for, voici le processus de réflexion permettant de transformer une tâche de routine en boucle:
Pour les nombres de 1 à 10, utilisez curl pour télécharger l’entrée Wikipédia de chaque numéro et enregistrez-la dans un fichier nommé «
wiki-number-(whatever the number is).html
»
À l’ancienne
Avec seulement 10 URL, nous pourrions définir quelques variables, puis copier-coller la commande a curl, 10 fois, en modifiant chaque ligne:
Et devinez quoi? Ça marche. Pour 10 URL, ce n’est pas une mauvaise solution, et c’est beaucoup plus rapide que de le faire à l’ancienne (le faire à partir de votre navigateur Web)
Réduire les répétitions
Même sans penser à une boucle, nous pouvons toujours réduire la répétition en utilisant des variables: l’URL de base, , et le nom du fichier de base ne changent jamais, alors assignons ces valeurs aux variables qui peut être réutilisé:
Application de la boucle for
À ce stade, nous avons simplifié le modèle jusqu’à présent que nous pouvons voir combien peu de changements avec chaque tâche séparée. Après avoir pris connaissance de la boucle for
, nous pouvons l’appliquer sans trop réfléchir (nous ajoutons également une commande de veille pour faire une pause entre les requêtes Web)
Génération d’un list
Dans la plupart des situations, la création d’une boucle for est facile; c « est la création de la liste qui peut être le dur labeur. Et si nous voulions rassembler les pages pour les numéros 1 à 100? C » est beaucoup de frappe.
Mais si nous laissons notre paresse dicter notre pensée, nous pouvons imaginer que compter de x à y semble être une tâche de calcul intrinsèque. Et ça l’est, et Unix a l’utilitaire seq
pour cela:
Génération d’une liste de non-nombres pour l’itération
De nombreuses tâches répétitives ne sont pas aussi simples que de compter de x à y, et donc le problème devient de savoir comment générer une liste non linéaire d’éléments? C’est essentiellement ce que fait l’art de la collecte et de la gestion des données. Mais faisons un scénario simple pour nous-mêmes:
Pour dix des mots de 10 lettres (ou plus) qui apparaissent au moins une fois dans un titre sur la page d’accueil actuelle de NYTimes.com, récupérez la page Wiktionnaire pour ce mot
Nous divisons cette tâche en deux parties:
- Récupère une liste de dix 10 + -lettre mots des titres de nytimes.com
- Passez ces mots à notre boucle for
Étape 1: Utilisation de l’utilitaire pup (ou de l’analyseur HTML en ligne de commande de votre choix):
Étape 2 (en supposant que la variable words
est transmise):
Découvrez Softwa re L’excellent guide de Carpentry sur les boucles for dans Bash