Introduction aux scripts shell Objectifs du document Ce document a pour objectif de vous faire découvrir les grands principes utilisés dans les scripts shell. Après quelques généralités, seront abordés les mécanismes de base sur lesquels les scripts shell reposent : composition de commandes (→ enchaînements, redirections) substitution de variables, d’expressions et de commandes protection de commandes Seront enfin présentées les structures de contrôle permettant l’exécution conditionnelle ou en boucle de portions de scripts. Qu’est-ce qu’un shell ? De manière générale, c’est un programme qui constitue une interface vers le système d’exploitation Le système d’exploitation est lui-même une interface vers le matériel. 2 formes : graphique → GUI : Graphical User Interface en ligne de commande → CLI : Command Line Interface Sur un système, plusieurs shells peuvent être disponibles simultanément. Exemples : CLI : bash (Bourne Again Shell ⇒ le plus répandu sur Linux), sh (Bourne shell ⇒ le shell “ancestral”), ksh (Korn shell), tcsh … GUI : KDE, Gnome … Qu’est-ce qu’un script shell ? Un fichier texte éditable avec n’importe quel éditeur de texte (nano, vi, Kate, KWrite…) Il contient essentiellement : des commandes Linux traditionnelles (ls, mkdir, chmod …) qui seront exécutées les unes après les autres et automatiquement par le shell des structures de contrôle pour faire des tests (→ exécution conditionnelle de commandes) , des boucles (→ exécution répétitive de commandes) des variables pour mémoriser des valeurs Il est directement interprétable par le shell pour lequel il a été conçu (→ pas de compilation). À quoi ça sert ? À automatiser certaines tâches : Lancer régulièrement des commandes disposant de nombreuses options sans avoir à les saisir à chaque fois et/ou se plonger dans la documentation pour déterminer lesquelles il faut employer Assurer le suivi et la maintenance de machines ou services dans le cadre de la supervision d’un parc informatique (→ surveillance des espaces disque, analyse de fichiers de journalisation…) Coder des outils : traitement automatique de fichiers texte, calcul Lancer l’exécution de logiciels qui nécessitent un paramétrage complexe. Le système Linux utilise lui-même abondamment les scripts shell dans sa phase d’initialisation (→ init System V, systemd). … En résumé, les scripts shell servent à être plus productif et notamment dans l’administration de systèmes informatiques. Un 1ier script fichier hello.sh (l’extension .sh est arbitraire mais couramment utilisée) : # Afficher un message d accueil (1) echo "Bonjour monde !" (2) 1 un commentaire qui débute par `#' 2 la commande qui permet d’afficher un message à l’écran Exécution du script par le shell sh (Bourne shell): $ sh hello.sh Bonjour monde ! Le “Shebang” Le “Shebang” est une séquence de 2 caractères (→ “#!”) à la suite desquels on indique le programme qui doit interpréter le script. Ceci va permettre de lancer un script shell comme n’importe quel autre programme en saisissant directement son nom (précédé de son chemin) plutôt que de le passer en argument à l’interpréteur devant l’exécuter. Rappel Sous Linux, il existe plusieurs interpréteurs de commande (→ sh, bash, tcsh …). Illustration : Intégration du “shebang” dans le fichier hello.sh : #! /bin/bash (1) # Afficher un message d accueil echo "Bonjour monde !" 1 on indique le shell pour lequel le script est conçu à l’aide de la séquence spéciale #! nommée shebang Le shebang doit impérativement constituer les 2 premiers caractères du fichier. Exécution du script : $ chmod +x hello.sh (1) $ ./hello.sh (2) Bonjour monde ! 1 on rend le script exécutable 2 on exécute le script simplement en tapant son nom dans le shell ⇒ celui-ci sera automatiquement interprété par le shell indiqué par le shebang (pas forcément le même que celui depuis lequel le script a été lancé) Rappel : Interaction avec un programme L’exécution de tout programme Linux suit toujours les mêmes règles : il débute son exécution après l’avoir invoqué depuis le shell en tapant son nom suivi ou non d’options et/ou arguments (→ correspond au contenu du char * argv[] dans un programme en langage C) il lit les saisies de l’utilisateur depuis le flux d’entrée standard (→ par défaut : le clavier) il affiche des messages sur le flux de sortie standard (→ par défaut : l’écran) pour informer l’utilisateur il alerte l’utilisateur en envoyant les messages d’erreur sur le flux d’erreur standard (→ par défaut : l’écran) il retourne enfin au système d’exploitation un compte-rendu d’exécution (exit code) sous forme d’entier dès qu’il se termine Exemple n°1 : $ ./hello.sh Bonjour monde ! $ echo $? 0 argv : {"./hello.sh"} stdin : "" stdout : "Bonjour monde !\n" stderr : "" exit code : 0 (← on l’affiche avec echo $?) Un 0 indique que tout s’est bien passé. Tout autre valeur indique une erreur. Exemple n°2 : $ mkdir /sbin/bidon mkdir: /sbin/bidon: Permission denied $ echo $? 1 argv : {"mkdir", "/sbin/bidon"} stdin : "" stdout : "" stderr : "mkdir: /sbin/bidon: Permission denied" exit code : 1 Exemple n°3 : $ read -p "Votre choix ? " Votre choix ? pizza $ echo $? 0 argv : {"read", "-p", "Votre Choix ?"} stdin : "pizza\n" stdout : "Votre choix ? " puis "pizza\n" stderr : "" exit code : 0 Composition de commandes Le principe d’exécution des programmes rappelé ci-dessus va permettre 2 fonctionnalités intéressantes : l’enchainement conditionnel de commandes exécution ou non d’une commande en fonction du code de retour de la précédente commande la redirection redirection des flux d’entrée, de sortie et d’erreur standard (stdin, stdout, stderr) vers/depuis des fichiers , redirection de la sortie standard d’une commande vers l’entrée standard d’une autre commande (→ tube ou pipe) Enchaînement conditionnel de commandes Séquence de commandes pouvant être interrompue selon la réussite ou l’échec de l’une d’entre elles Mécanisme reposant sur la valeur des codes de sortie des programmes (0 = OK, <>0 = NOK) $ cmd1 && cmd2 && cmd3 && ... ⇒ Exécute cmd2 si cmd1 réussit puis cmd3 si cmd2 réussit … $ cmd1 || cmd2 || cmd3 || ... ⇒ Exécute cmd2 si cmd1 échoue puis cmd3 si cmd2 échoue … $ cmd1 ; cmd2 ; cmd3 ; ... ⇒ Exécute cmd1 puis cmd2 puis cmd3 … quel que soient leurs résultats d’exécution (réussite ou échec) Illustration Sous Linux il existe 2 commandes false et true qui ne font rien mais … : qui échoue systématiquement pour false (→ exit code = 1) qui réussit toujours pour true (→ exit code = 0) Qu’affichent les enchainements de commandes suivants sachant que la commande echo réussit toujours ? $ echo -n 'Hello ' ; false ; echo 'world !' $ echo -n 'Hello ' && false ; echo 'world !' $ echo -n 'Hello ' && false || echo 'world !' $ echo -n 'Hello ' && false && echo 'world !' $ echo -n 'Hello ' && true || echo 'world !' L’option -n spécifie à la commande echo de ne pas retourner à la ligne. Réponse : $ echo -n 'Hello ' ; false ; echo 'world !' Hello world ! $ echo -n 'Hello ' && false ; echo 'world !' Hello world ! $ echo -n 'Hello ' && false || echo 'world !' Hello world ! $ echo -n 'Hello ' && false && echo 'world !' Hello $ echo -n 'Hello ' && true || echo 'world !' Hello Attention à la priorité des opérateurs (→ précédence) cmd1 || cmd2 && cmd3 = (cmd1 || cmd2) && cmd3 cmd1 || cmd2 && cmd3 ≠ cmd1 || (cmd2 && cmd3) Exemple : $ echo -n 'Hello ' || false && echo 'world !' Hello world ! $ (echo -n 'Hello ' || false) && echo 'world !' Hello world ! $ echo -n 'Hello ' || (false && echo 'world !') Hello Redirection des flux standards : ‘>’, ‘>>’, ‘<’ $ <cmd> > out.txt (1) $ <cmd> >> out.txt (2) $ <cmd> < in.txt (3) 1 Exécute <cmd> et envoie sa sortie standard dans le fichier out.txt au lieu de l’écran. Si le fichier n’existe pas, il est créé Si le fichier existe, son contenu d’origine est écrasé 2 idem sauf que la sortie standard est ajoutée au contenu du fichier out.txt s’il existe (→ on ne perd pas son contenu d’origine). 3 l’entrée standard de cmd est lue depuis le fichier in.txt et non depuis le clavier Exemple n°1 : Rediriger la sortie de la commande echo dans le fichier out.txt $ echo "Bonjour" > out.txt (1) $ cat out.txt Bonjour $ echo "Salut" > out.txt (2) $ cat out.txt Salut $ echo " tout le monde !" >> out.txt (3) $ cat out.txt Salut tout le monde ! 1 on envoie “Bonjour” dans le fichier out.txt au lieu de l’écran 2 on envoie “Salut” dans out.txt. Puisque le fichier existe déjà, son contenu est écrasé 3 on envoie “tout le monde !” à la suite du contenu existant de out.txt Exemple n°2 : lister dans un même fichier le contenu de 2 répertoires $ ls /home/bonnie >catalog.txt ; ls /home/clyde >>catalog.txt La commande tee de Linux peut être très utile : elle copie son entrée standard (stdin) dans sa sortie standard (stdout) et dans un fichier que l’on spécifie en argument de la commande. Cela permet, par exemple, de garder dans un fichier une trace de la sortie d’une commande tout en permettant de la relayer à une autre commande (cf. Les tubes). Pour plus d’informations sur la commande tee, consulter par exemple Linux and Unix tee command tutorial with examples . Here documents : ‘<<’ L’opérateur << possède une signification sensiblement différente : il est utilisé dans le cadre de ce qu’on appelle les here documents. Un here document permet de “simuler” un fichier en indiquant son contenu en ligne. Exemple : Afficher le nombre de lignes du here document dont le contenu est délimité par la chaîne arbitraire FIN (FIN doit impérativement être “collé” à <<). $ wc -l <<FIN (1) > ligne n°1 > ligne n°2 > ligne n°3 > FIN 3 (2) $ 1 appel de la commande wc -l qui compte le nombre de ligne de ce qu’il lui est fournit en entrée, c’est-à-dire, ici, le here document 2 le here document contient effectivement 3 lignes Redirection du flux d’erreur : ‘2>&1’ ou '`&>`" Il est possible de rediriger la sortie d’erreur et la sortie standard dans un même fichier. Dans de nombreux scripts, on utilise la séquence 2>&1 à cet effet. Exemple : compter les lignes de 2 fichiers dont 1 n’existe pas $ wc -l hello.sh fichier_inexistant > errout.txt 2>&1 (1) $ cat errout.txt (2) wc: fichier_inexistant: open: No such file or directory 3 hello.sh 3 total 1 La commande wc ne provoque aucun affichage 2 le fichier errout.txt contient à la fois l’erreur (→ stderr) sur la 1ière ligne du fichier et le résultat de la commande wc appliquée au fichier hello.sh sur les 2 lignes suivantes (→ stdout). Interprétation de la commande : On redirige d’abord la sortie standard de la commande vers errout.txt puis on redirige la sortie d’erreur (représentée par le 2 dans 2>&1) vers l’endroit où est redirigée la sortie standard (représentée par le 1 dans 2>&1) ⇒ les sorties standard et d’erreurr sont redirigées dans le même fichier. La page de manuel de bash suggère une autre syntaxe pour réaliser cette commande : $ wc -l hello.sh fichier_inexistant &> errout.txt (1) 1 on utilise la syntaxe &> plutôt que 2>&1 Malgré une meilleure lisibilité, la 1ière syntaxe est encore largement répandue. Utilisation fréquente de la redirection 2>&1 : rendre “muet” un programme $ yes > /dev/null 2>&1 On redirige la sortie standard et d’erreur de la commande yes (→ envoie à l’infini le caractère ‘y’ sur stdout) sur le fichier /dev/null qui offre la particularité d’ignorer et de perdre tout ce qu’on écrit dedans ⇒ ceci permet de réduire à néant tout message émis sur le flux standard ou d’erreur : aucun affichage aucune utilisation de l’espace disque Attention à l’emplacement de 2>&1 Une commande <cmd> 2>&1 > /dev/null ne redirigerait que la sortie standard vers /dev/null. En effet, ici, on redirige stderr vers stdout avant que celui-ci ne soit redirigé sur /dev/null. La preuve “en image” : $ wc -l fichier_inexistant 2>&1 > /dev/null wc: fichier_inexistant: open: No such file or directory Les tubes Les tubes sont unt type de redirection qui est également très fréquemment employé dans les scripts Syntaxe $ cmd1 | cmd2 (1) 1 On exécute cmd1 puis cmd2 en redirigeant la sortie standard de cmd1 sur l’entrée standard de cmd2. Exemple : Compter le nombre de fichiers dans le répertoire /var/log/apache2 $ ls /var/log/apache2/ | wc -l 3 # Sensiblement équivalent à : $ ls /var/log/apache2/ > fichier.txt $ wc -l < fichier.txt 3 # ...mais le résultat intermédiaire n'est pas stocké # (-> on gagne 36 octets sur le disque) $ ls -l fichier.txt -rw-r--r--@ 1 claude staff 36 7 avr 14:47 fichier.txt Question Soit le contenu de répertoire suivant : $ ls -l *.txt -rw-r--r-- 1 claude staff 1024 31 mar 21:40 a.txt -rw-r--r-- 1 claude staff 512 31 mar 21:40 b.txt -rw-r--r-- 1 claude staff 1536 31 mar 21:40 c.txt Sachant que : head -n 1 affiche la 1ière ligne de son entrée standard sort affiche par ordre lexicographique ce qui lui est fourni Quelle commande parmi celles indiquées ci-dessous permet de lister uniquement le fichier le plus petit sachant que tous les fichiers ayant les mêmes droits, propriétaires et groupes, leur affichage dans la commande ls ne diffère qu’à partir de la colonne indiquant leur taille : $ sort | head -n 1 | ls -l *.txt $ head -n 1 | ls -l *.txt | sort $ ls -l *.txt | head -n 1 | sort $ head -n 1 | sort | ls -l *.txt $ ls -l *.txt | sort | head -n 1 $ sort | ls -l *.txt | head -n 1 Réponse : $ ls -l *.txt | sort | head -n 1 # c'est celle-ci !! # la preuve : $ ls -l *.txt | sort | head -n 1 -rw-r--r--@ 1 claude staff 512 31 mar 21:40 b.txt L’utilisation des tubes n’est possible qu’avec les commandes de type “filtre” c.-à-d. les commandes qui acceptent de prendre leur entrée standard depuis la sortie d’un tube (ex. sort, head mais pas ls). Il existe néanmoins une solution qui consiste à utiliser la commande xargs. Cette commande capture son entrée standard et la redistribue à la commande qu’on lui donne en argument. Exemple : $ echo "/home\n /var/tmp" | xargs ls (1) 1 Liste le contenu des répertoires /home et /var/tmp Consulter internet pour des exemples plus complets. Ex. : Linux commands: xargs . Substitution Un shell Linux est capable d’évaluer un certain nombre d’expressions au cours de l’exécution d’un script. Lorsqu’il en rencontre une, il la remplace/substitue par le résultat de son évaluation puis reprend l’interprétation du script Parmi les expressions candidates, on trouve : les variables, les caractères génériques ou jokers (→ wildcards) les expressions arithmétiques et bit-à-bit les commandes Substitution de variables Variable : nom auquel on associe une valeur Définition d'1 variable : <nom_variable>=<valeur> Utilisation d'1 variable : $<nom_variable> ou ${<nom_variable>} Plusieurs types de variables : variables utilisateurs ⇒ variables définies par l’utilisateur. ex. : $mon_age variables d’environnement ⇒ variables définies par le système. ex. : $PATH variables internes ⇒ variables définies par le shell. ex. : $@ Variables utilisateurs Exemple de création/utilisation de variables utilisateur : #! /bin/sh # script : uservariable.sh question= "Tu fais koi ?" option=IR formation="BTS CIEL" echo $question echo "J'suis en $formation_$option ...euh... ${formation}_$option)" $ chmod +x uservariable.sh $ ./uservariable.sh Tu fais koi ? J'suis en IR ...euh... BTS CIEL_IR Noter la différence entre $formation_$option et ${formation}_$option. Dans la 1ière forme, le shell cherche une variable nommée formation_ (← le `_' est un caractère autorisé dans le nom d’une variable), ne la trouve pas et la remplace donc par une chaîne vide. Variables d’environnement Exemple avec variable d’environnement : $ printenv (1) TERM_PROGRAM=Apple_Terminal SHELL=/bin/bash [...] HOME=/Users/claude LOGNAME=claude $ echo "Mon nom d'utilisateur est $LOGNAME et mon shell est $SHELL." Mon nom d'utilisateur est claude et mon shell est /bin/bash. 1 : la commande printenv affiche les variables d’environnement Variables internes Le shell définit un certain nombre de variables spéciales très utiles pour écrire les scripts : $0, $1, $2, … : les constituants de la ligne de commande qui a invoqué le script $0 : le nom du script $1, $2, … : les arguments du script $@ : la liste des arguments ( $1 + $2 + …) $# : le nombre d’arguments fournis au script $? : le code de retour du dernier programme/script exécuté … Exemple : #! /bin/sh # script : internalvariables.sh echo "Hello from script $0 -> $# argument(s) provided" echo "1st arg : $1" echo "2nd arg : $2" $ ./internalvariable.sh A Hello from script ./internalvariable.sh -> 1 argument(s) provided 1st arg : A 2nd arg : $ ./internalvariable.sh A B Hello from script ./internalvariable.sh -> 2 argument(s) provided 1st arg : A 2nd arg : B $ ./internalvariable.sh A B C Hello from script ./internalvariable.sh -> 3 argument(s) provided 1st arg : A 2nd arg : B $ ./internalvariable.sh "A B" C Hello from script ./internalvariable.sh -> 2 argument(s) provided 1st arg : A B 2nd arg : C Caractères génériques Certains caractères prennent une signification particulière pour le shell (cf. `<', `>', ’|', …) ⇒ ce sont les Méta-caractères Les méta-caractères suivants sont utilisés comme “joker” pour les noms de fichier ou de répertoire : ?, *, !, [ et ]. ? → remplace n’importe quel caractère individuel * → remplace un ensemble de caractères consécutifs [<plage_valeurs>] → remplace un caractère parmi ceux spécifiés dans <plage_valeurs> Si on remplace <plage_valeurs> par !<plage_valeurs> ceci inverse la signification de Exemples : # Liste les dossiers débutant par 'D' $ ls -d D*/ Desktop/ Documents/ Downloads/ # Liste les dossiers débutant par 'D' et se terminant par 'p' $ ls -d D*p/ Desktop/ # Liste les dossiers dont la 2ième lettre est 'o' et la dernière est 's' $ ls -d ?o*s/ Documents/ Downloads/ # Liste les dossiers débutant par 'D' et dont la 3ième lettre est 's' ou 'w' $ ls -d D?[sw]*/ Desktop/ Downloads/ # Liste les dossiers débutant par 'D' et dont la 3ième lettre n'est ni 's' ni 'w' $ ls -d D?[!sw]*/ Documents/ Expressions arithmétiques & bit-à-bit Le shell est capable d’évaluer des expressions arithmétiques simples et bit-à-bit avec la notation suivante : $((<expression>)) Exemples : # Division entière $ echo $((10/6)) 1 # Reste de la division entière (modulo) $ echo $((10%6)) 4 # Décalage d'un rang vers la droite $ echo $((10>>1)) 5 # OU bit à bit $ echo $((10|7)) 15 Substitution de commandes Le shell sait capturer la sortie standard d’une commande pour l’utiliser par la suite. Syntaxe : $( <commande> ) On peut rencontrer une autre syntaxe qui n’est pas recommandée : ` <commande> ` Exemple : # On mémorise dans 'annee' la sortie standard de la commande : # date "+%Y" puis on affiche cette variable pour avoir l'année courante $ annee=$(date "+%Y") $ echo $annee 2023 # On utilise ensuite la variable $ echo "L'an prochain, nous serons en $((annee+1))." L'an prochain, nous serons en 2024. Protections des expressions On a vu que certains caractères étaient interprétés par le shell. Pour éviter cette interprétation, 3 moyens existent : l’antislash ou échappement (\) → annule le sens particulier du méta-caractère qui le suit. Exception : l’antislash suivi d’un retour à la ligne ⇒ utilisé, par ex., pour continuer la saisie d’une commande à la ligne suivante les apostophes ('...') → tous les caractères compris entre les apostrophes perdent leur signification spéciale. les doubles guillemets ("…") → annule le sens particulier des caractères qu’ils renferment à l’exception de $, ` (backquote) et, dans certaines conditions, de | puis ! Exécution conditionnelle : if/then/else/fi Comme tout langage de programmation, le shell propose une structure qui permet d’exécuter du code ou non selon qu’une condition est remplie ou non Syntaxe : if cmd1 then cmd2 else cmd3 fi # OU de manière plus condensée if cmd1 ; then cmd2 ; else cmd3 ; fi cmd2 exécutée si cmd1 exécutée avec succès cmd3 exécutée si cmd1 a échoué cmd1 est la plupart du temps la commande test qui permet d’évaluer une condition Exemple : #!/bin/bash state="on" if test "$state" = "on" then echo "Allumé !" else echo "Eteint !" fi Toujours entourer les références aux variables par des double côtes lorsqu’elles sont employées dans des conditions de façon à traiter correctement des variables vides. Exemple : #!/bin/bash # state="on" (1) if test $state = "on" (2) then echo "Allumé !" else echo "Eteint !" fi 1 on inactive la déclaration de la variable avec un commentaire 2 on ne met pas la référence à la variable entre double côtes L’exécution de ce script provoque une erreur : $ ./dummy-test.sh ./dummy-test.sh: line 4: [: =: unary operator expected Eteint Exécution conditionnelle : la commande test Exemples de syntaxe : test -f <fichier> → VRAI (code de retour 0) si le fichier existe test -z <chaîne> → VRAI si la chaîne de caractères est vide test <chaîne1> = <chaîne2> →VRAI les 2 chaînes sont identiques test <nombre1> -lt <nombre2> → VRAI si <valeur1> est plus petite (less than) que <valeur2> La commande test est tellement commune, qu’une abbréviation standard (i.e conforme POSIX) existe pour elle : test <condition> ⇆ [ <condition> ] Exemple : test -f <fichier> ⇆ [ -f <fichier> ] Il existe un autre raccourci pour la commande test mais qui n’est valable que dans bash: test <condition> ⇆ [[ <condition> ]] cette version offre plus de possibilités que la précédente Les espaces sont obligatoires autour de la condition dans la syntaxe [␣<condition>␣] Exemple n°1 : test de valeur de variables de type chaine ou numérique $ cat dummy-test.h #!/bin/bash state="on" nombre=1789 if [ "$state" = "on" ] then echo "Allumé !" else echo "Eteint !" fi if [ $(("$nombre" % 2)) -eq 0 ] then echo "Nombre pair" else echo "Nombre impair" fi $ ./dummy-test.sh Allumé ! Nombre impair Exemple n°2 : Déterminer le siècle de l’année courante $ cat getcentury.sh #! /bin/sh annee=$(date "+%Y") if test "$annee" -lt 2001 # ou [ "$annee" -lt 2001 ] then echo "$annee -> 20ième siècle" else echo "$annee -> 21ième siècle" fi $ ./getcentury 2023 -> 21ième siècle Exécution conditionnelle : Combinaison de plusieurs conditions il est possible de combiner plusieurs conditions : Ex. : Combinaison de 2 conditions avec un OU logique if [ cond1 ] || [ cond2 ] ; then cmd1 ; fi (1) 1 cmd1 sera exécutée si l’une ou l’autre des conditions cond1 et cond2 est vérifiée voire les 2. Il existe 3 opérateurs logiques pour combiner des conditions : le OU logique ⇒ codé || le ET logique ⇒ codé && le NON logique ⇒ codé ! Exemple : #! /bin/sh temperature=16 etatChauffage="OK" if [ $temperature -lt 18 ] && [ ! $etatChauffage == "HS" ] then echo "Déclenchement du chauffage" (1) fi 1 Le chauffage n’est déclenché que si la température est inférieure à 18°C et que le chauffage n’est pas HS. Exécution en boucle Le shell propose plusieurs structures qui permettent d’exécuter des portions de script en boucle : for…do…done, while…do…done Le for…do…done est utilisé lorsque le nombre d’itérations est connu à l’avance 2 formes : for <variable> in <list> ; do <cmds> … ; done ⇒ <variable> prend successivement les valeurs présentes dans <list> et la séquence de commandes <cmds> … est exécutée suite à chaque affectation. for (( <expr1> ; <expr2> ; <expr3> )) ; do <cmds> … ; done ⇒ <expr1> est évaluée 1 fois puis <expr2> est évaluée de manière répétitive jusqu’à ce qu’elle prenne la valeur 0. A chaque fois que <expr2> est évaluée comme différente de 0, la séquence de commandes <cmds> … est exécutée et <expr3> est évaluée. Exemple 1 : $ cat comptine1.sh #! /bin/bash for i in {1..3} ; do echo -n "$i, "; done (1) echo "... nous irons au bois" $ ./comptine1.sh 1, 2, 3, ... nous irons au bois 1 on affiche successivement les valeurs que prend la variable i durant l’exécution de la boucle Exemple 2 : $ cat comptine2.sh #! /bin/bash for ((i=4; i < 7; i++)) ; do echo -n "$i, "; done (1) echo "... cueillir des cerises" $ ./comptine2.sh 4, 5, 6, ... cueillir des cerises 1 on fait la même chose que dans l’exemple précédent mais, cette fois-ci, avec la 2ème syntaxe Pour finir Ce cours a permis d’aborder les mécanismes de base proposés par bash pour réaliser des scripts shell. La puissance des scripts shell ne réside cependant pas uniquement sur ces mécanismes mais aussi sur la multitude et la cohérence des commandes mises à disposition par Linux. La découverte de ces commandes dépasse le cadre de ce document. Il est donc recommandé de d’abord se renseigner sur les commandes “incontournables” de Linux avant d’implémenter des scripts shell “sérieux”. Par exemple, des commandes comme tee, xargs, sed, grep, find (notamment avec son option -exec → voir Using the find -exec Command Option ), awk… peuvent être d’une grande utilité. 🞄 🞄 🞄 Shell Linux Windows