Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
|
console:script_shell [Le 13/01/2008, 16:39] 82.235.82.92 |
— (Version actuelle) | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| - | {{tag>Programmation développement}} | ||
| - | ---- | ||
| - | ======Introduction aux scripts shell====== | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | ===== Présentation ===== | ||
| - | |||
| - | Un script shell permet d'automatiser une série d'opérations. Il se présente sous la forme d'un fichier contenant une ou plusieurs commandes qui seront exécutées de manière séquentielle. | ||
| - | |||
| - | === Règles de base lors de l'écriture d'un script === | ||
| - | |||
| - | * Des vérifications approfondies doivent être effectuées sur TOUTES les commandes utilisées. | ||
| - | * Des commentaires détaillés doivent apparaître lors de chaque étape. De même, chaque étape doit être suivie d'un "echo <voici ce que je fais>" (particulièrement utile notamment lors du débuggage). | ||
| - | * Lors d'une mise a jour, un fil de discussion doit être précisé pour tracer les bugs éventuels. | ||
| - | * Avertir les utilisateurs les dégâts que peuvent causer les commandes utiliser. (Ces deux dernières remarques ne concernent bien sûr que les scripts que l'on souhaite diffuser.) | ||
| - | |||
| - | Évidemment ces conseils sont utiles au débutant... | ||
| - | <note tip>Astuce: Le plus important dans tout programme est l'algorithme utilisé</note> | ||
| - | Exemple: | ||
| - | Supposons que vous avez une base de données, avec 3 catégories d'enregistrements possible: | ||
| - | éléphant bleu, éléphant blanc, éléphant rose ayant chacun 30 individus. | ||
| - | Votre script doit compter le nombre d'éléphant bleu et blanc. | ||
| - | Deux possibilité s'offre a vous: | ||
| - | - calculer le nombre d'éléphant bleu + éléphant blanc | ||
| - | ou | ||
| - | - calculer le nombre d'éléphant total - nombre d'éléphant rose | ||
| - | |||
| - | Quel algorithme choisissez vous? | ||
| - | Résultat: Le premier car dans le deuxième il faut d'abord calculer le nombre d'éléphant total, donc un calcul en plus. | ||
| - | <note help>Vous comprenez ?</note> | ||
| - | OUUUUUUIIIIIIIIIIIIIIIIIIIIIII ! | ||
| - | |||
| - | ===Ecrire un script=== | ||
| - | |||
| - | Si vous voulez écrire un programme sh, vous avez deux possibilités : | ||
| - | * soit vous tapez dans un shell toutes les commandes | ||
| - | * ou alors vous rassemblez toutes les instructions copier par ci par là dans un fichier sh. | ||
| - | |||
| - | A titre d'exemple, saisissez ces quelques ligne dans votre éditeur préféré : | ||
| - | |||
| - | #!/bin/bash | ||
| - | # indique au système que l'argument qui suit est le programme utilisé pour exécuter ce fichier | ||
| - | # En cas général les "#" servent à faire des commentaire comme ici | ||
| - | echo Mon premier script | ||
| - | echo Liste des fichiers : | ||
| - | ls -la | ||
| - | | ||
| - | exit 0 | ||
| - | |||
| - | Le résultat de ce script est d'écrire à l'écran "Mon premier script", puis | ||
| - | en dessous "Liste des fichiers :", et enfin la liste des fichiers avec la | ||
| - | commande `ls -la`. | ||
| - | |||
| - | Comme vous l'avez compris, la commande `echo` sert à écrire | ||
| - | quelque chose à l'écran. | ||
| - | |||
| - | <note warning>Cependant il vous faudra extrêmement bien faire attention a tout ces morceaux de code. Leur utilisation sans connaissance de votre part pourrait vous faire perdre de précieuses données.</note> | ||
| - | |||
| - | |||
| - | ====Exécuter un script==== | ||
| - | D'ici, j'entends déjà les débutants dire : | ||
| - | <note help>Mais comment on exécute ce script ?</note> | ||
| - | |||
| - | Et bien il suffit de se placer dans le dossier où est le script, et de lancer | ||
| - | |||
| - | bash nom_du_script | ||
| - | |||
| - | Si vous voulez l'exécuter avec ".", il faut | ||
| - | le rendre exécutable avec `chmod`. Pour ceci tapez dans le shell la commande | ||
| - | qui suit : | ||
| - | |||
| - | chmod +x nom_du_script | ||
| - | |||
| - | Puis vous pouvez exécuter le script en faisant : | ||
| - | |||
| - | ./nom_du_script | ||
| - | |||
| - | ====Les différents types de shells==== | ||
| - | |||
| - | Comme vous avez sûrement du l'entendre, il existe différents types de shells, dont le plus connu est, comme vous l'aurez deviné, 'shell,' qui signifie //coquille//. Il existe aussi: | ||
| - | |||
| - | * bash (//Bourne Again SHell//) : conçu par le projet GNU, shell linux ; | ||
| - | * rbash : un shell restreint basé sur bash. Il existe de nombreuses variantes de bash ; | ||
| - | * csh, tcsh : shells C, créés par Bill Joy de Berkeley ; | ||
| - | * zsh, shell C écrit par Paul Falstad ; | ||
| - | * ksh,pdksh : shells korn, écrits par David Korn ; | ||
| - | * rc : shell C, lui aussi conçu par le projet GNU ; | ||
| - | * tclsh : shell utilisant Tcl ; | ||
| - | * wish : shell utilisant Tk ; | ||
| - | |||
| - | Il existe bien entendu beaucoup d'autre type de shells. | ||
| - | |||
| - | Shell (sh) est en fait un lien vers /bin/bash, tout comme rbash. | ||
| - | |||
| - | =====Les structures de contrôle===== | ||
| - | |||
| - | ====Les tests : `if`==== | ||
| - | Avant de commencer à faire des scripts de 1000 lignes, il serait intéressant | ||
| - | de voir comment se servir des variables, et des instructions if, then, elif, | ||
| - | else, fi. Cela permet par exemple de faire réagir le script de manière différente, selon | ||
| - | la réponse de l'utilisateur à une question. | ||
| - | |||
| - | En bash, les variables ne se déclarent généralement pas | ||
| - | avant leurs utilisations, on les utilise directement et elles sont créées | ||
| - | lors de sa première mise en œuvre. | ||
| - | |||
| - | Pour pouvoir voir la valeur d'une variable il faut faire précéder son nom du caractère "$". | ||
| - | ==Exemple== | ||
| - | |||
| - | #!/bin/sh | ||
| - | echo -n "Voulez-vous voir la liste des fichiers Y/N : " | ||
| - | read ouinon | ||
| - | if [ "$ouinon" = "y" ] || [ "$ouinon" = "Y" ]; then | ||
| - | { | ||
| - | echo "Liste des fichiers :" | ||
| - | ls -la | ||
| - | } | ||
| - | elif [ "$ouinon" = "n" ] || [ "$ouinon" = "N" ]; then | ||
| - | { | ||
| - | echo "Ok, bye! " | ||
| - | } | ||
| - | else | ||
| - | { | ||
| - | echo "Il faut taper Y ou N!! Pas $ouinon" | ||
| - | } | ||
| - | fi | ||
| - | |||
| - | ==Explication== | ||
| - | |||
| - | Ce script peut paraître simple à première vue mais certaines | ||
| - | choses prêtent à confusion et ont besoin d'être expliquées en détail. | ||
| - | |||
| - | Tout abord, le `echo -n` permet de laisser le curseur sur la même ligne, ce | ||
| - | qui permet à l'utilisateur de taper la réponse après la question (question | ||
| - | d'esthétique). | ||
| - | |||
| - | L'instruction `read` permet d'affecter une | ||
| - | valeur ou un caractère à une variable quelconque, en la demandant à l'utilisateur. | ||
| - | (NOTE: En bash, la variable est considérée comme une chaîne même si celle-ci contient | ||
| - | une valeur numérique, et les majuscules sont considérées différente des minuscules, $M != $m). | ||
| - | |||
| - | Ensuite vient l'instruction conditionnelle `if`. Elle est suivie d'un "[" | ||
| - | pour délimiter la condition. Attention, la variable est mise entre guillemets | ||
| - | car dans le cas où la variable est vide, le shell ne retourne pas d'erreur, mais en | ||
| - | cas contraire, l'erreur produite ressemble à: | ||
| - | |||
| - | [: =: unaryoperator expected | ||
| - | |||
| - | L'opérateur `||` signifie "ou" (il existe aussi `&&` pour "et"). | ||
| - | On peut définir une table de vérité pour ces deux opérateurs, où //1// représente une assertion vraie et //0// une assertion fausse : | ||
| - | |||
| - | ==Table de vérité de ||== | ||
| - | ^ Comparaison ^ Résultat ^ calcul ^ | ||
| - | | 0 ou 0 | 0 | 0+0=0 | | ||
| - | | 0 ou 1 | 1 | 0+1=1 | | ||
| - | | 1 ou 0 | 1 | 1+0=1 | | ||
| - | | 1 ou 1 | 1 | 1+1=1 | | ||
| - | |||
| - | Dès que l'une des deux assertions est vérifiée, la condition globale l'est aussi. | ||
| - | |||
| - | ==Table de vérité de &&== | ||
| - | ^ Comparaison ^ Résultat ^ calcul ^ | ||
| - | | 0 et 0 | 0 | 0*0=0 | | ||
| - | | 0 et 1 | 0 | 0*1=0 | | ||
| - | | 1 et 0 | 0 | 1*0=0 | | ||
| - | | 1 et 1 | 1 | 1*1=1 | | ||
| - | |||
| - | Les deux assertions doivent être vérifiées pour que la condition le soit aussi. | ||
| - | |||
| - | Enfin, on ferme le crochet, suivi d'un point virgule ou d'un saut de ligne pour exécuter la | ||
| - | commande `then` qui applique ce qui vient après, si la condition est respectée. | ||
| - | |||
| - | Les "{" servent à bien délimiter le bloc d'instructions suivant le `then`, cela permet | ||
| - | juste de facilement lire le code, de mieux se repérer. | ||
| - | |||
| - | Ensuite, `elif` sert à exécuter une autre série d'instructions, si la condition décrite par `if` n'est pas respectée, et si celle fournie après ce `elif` l'est. | ||
| - | |||
| - | Enfin, `else` sert à exécuter un bloc si les deux conditions précédentes ne sont pas respectées. (ah les jeunes, ils respectent plus rien de nos jours :) ). | ||
| - | |||
| - | `fi` indique la fin de notre bloc d'instructions if, ce qui permet de voir où se termine toute notre portion de code soumis à une condition. | ||
| - | |||
| - | J'ai quelques petites commandes pratiques à vous donner : | ||
| - | |||
| - | sh -n nom_du_fichier | ||
| - | |||
| - | Cette commande vérifie la syntaxe de toutes les commandes du script, pratique quand on débute et pour les codes volumineux. | ||
| - | |||
| - | sh -u nom_du_fichier | ||
| - | |||
| - | Celle-ci sert à montrer les variables qui n'ont pas été utilisées pendant l'exécution du programme. | ||
| - | |||
| - | Voici le tableau des opérateurs de comparaison, ceux-ci peuvent s'avérer utiles pour diverses raisons, nous verrons un peu plus loin un exemple: | ||
| - | |||
| - | === Opérateurs de comparaison === | ||
| - | |||
| - | ^ Syntaxe ^ Fonction réalisée ^ | ||
| - | | -e fichier | Vrai si fichier existe. | | ||
| - | | -d fichier | Vrai si fichier existe et est un répertoire. | | ||
| - | | -f fichier | Vrai si fichier existe et est un fichier 'normal'.| | ||
| - | | -w fichier | Vrai si fichier existe et est en écriture. | | ||
| - | | -x fichier | Vrai si fichier existe et est exécutable. | | ||
| - | | f1 -nt f2 | Vrai si f1 est plus récent que f2. | | ||
| - | | f1 -ot f2 | Vrai si f1 est plus vieux que f2. | | ||
| - | |||
| - | Exemple, vérifier qu'un fichier existe: | ||
| - | |||
| - | #!/bin/sh | ||
| - | | ||
| - | echo -n "Entrez un nom de fichier: " | ||
| - | read file | ||
| - | if [ -e "$file" ]; then | ||
| - | { | ||
| - | echo "Le fichier existe!" | ||
| - | } | ||
| - | else | ||
| - | { | ||
| - | echo "Le fichier n'existe pas, du moins n'est pas dans le répertoire d'exécution du script" | ||
| - | } | ||
| - | fi | ||
| - | exit 0 | ||
| - | |||
| - | La seule chose qui prête à confusion est que l'on vérifie seulement si le fichier 'file' est dans le répertoire où le script à été exécuté. | ||
| - | |||
| - | ====La commande `while`==== | ||
| - | |||
| - | La commande while exécute ce qu'il y a dans son bloc tant que la condition | ||
| - | est respectée: | ||
| - | |||
| - | #!/bin/sh | ||
| - | | ||
| - | cmpt=1 | ||
| - | cm=3 | ||
| - | echo -n "Mot de passe : " | ||
| - | read mdp | ||
| - | | ||
| - | while [ "$mdp" != "ubuntu" ] && [ "$cmpt" != 4 ]; do | ||
| - | echo -n "Mauvais mot de passe, plus que "$cm" chance(s): " | ||
| - | read mdp | ||
| - | cmpt=$(($cmpt+1)) | ||
| - | cm=$(($cm-1)) | ||
| - | done | ||
| - | echo "Non mais, le brute-force est interdit en France !!" | ||
| - | exit 0 | ||
| - | |||
| - | On retrouve des choses déjà abordées avec `if`. | ||
| - | Le `&&` sert à symboliser un "et", cela implique que deux conditions sont | ||
| - | à respecter. Le `do` sert à exécuter ce qui suit si la condition est respectée. | ||
| - | Si elle ne l'est pas, cela saute tout le bloc (jusqu'a `done`). | ||
| - | Je vous vois d'ici dire : | ||
| - | >Mais qu'est-ce que c'est ce truc avec cette syntaxe zarbi au milieu ? | ||
| - | Cette partie du code sert tout simplement à réaliser | ||
| - | une opération arithmétique. A chaque passage, | ||
| - | 'cmpt = cmpt+1' et 'cm = cm-1'. | ||
| - | |||
| - | `while` permet de faire exécuter la portion de code un nombre déterminé de fois. | ||
| - | La commande `until` fait la même chose que la commande `while` mais en inversant. | ||
| - | C'est a dire qu'elle exécute le bloc jusqu'a ce que la condition soit vraie, donc elle | ||
| - | s'emploie exactement comme la commande `while`. | ||
| - | |||
| - | ====La commande `case`==== | ||
| - | |||
| - | Regardons la syntaxe de cette commande, qui n'est pas une des plus simples : | ||
| - | |||
| - | case variable in | ||
| - | modèle [ | modèle] ...) instructions;; | ||
| - | modèle [ | modèle] ...) instructions;; | ||
| - | ... | ||
| - | esac | ||
| - | |||
| - | Cela peut paraître complexe mais on s'y habitue quand on l'utilise. | ||
| - | >Mais a quoi sert cette commande ? | ||
| - | Elle sert à comparer le contenu d'une variable à des modèles différents. Les ;; sont indipensables car il est possible de placer plusieurs instructions entre un modèle et le | ||
| - | suivant. Les ;; servent donc à identifier clairement la fin d'une instruction et | ||
| - | le début du modèle suivant. | ||
| - | |||
| - | Exemple: | ||
| - | |||
| - | #!/bin/sh | ||
| - | | ||
| - | echo -n "Etes-vous fatigué ? " | ||
| - | read on | ||
| - | | ||
| - | case "$on" in | ||
| - | oui | o | O | Oui | OUI ) echo "Allez faire du café !";; | ||
| - | non | n | N | Non | NON ) echo "Programmez !";; | ||
| - | * ) echo "Ah bon ?";; | ||
| - | esac | ||
| - | exit 0 | ||
| - | |||
| - | Je crois que la seule chose qui mérite vraiment d'être expliquée est `* )`. | ||
| - | Cela indique tout simplement l'action à exécuter si la réponse donnée n'est aucune de celle données précédemment. | ||
| - | |||
| - | |||
| - | Il existe aussi plusieurs structures pour les modèles, telles que: | ||
| - | |||
| - | |||
| - | case "$truc....." in | ||
| - | [nN] *) echo "Blablabla...";; | ||
| - | n* | N* ) echo "Bla....";; | ||
| - | |||
| - | Et plein d'autres encore... | ||
| - | |||
| - | ==On mélange tout ça== | ||
| - | |||
| - | Pour vous donner une idée précise de ce que peuvent réaliser toutes ces instructions, | ||
| - | j'ai fait un petit script sensé refaire un prompt avec quelques commandes basiques : | ||
| - | |||
| - | #!/bin/bash | ||
| - | | ||
| - | clear | ||
| - | echo | ||
| - | echo #################### Script ############################ | ||
| - | echo | ||
| - | echo ############################# | ||
| - | echo -n LOGIN: | ||
| - | read login | ||
| - | echo -n Hôte: | ||
| - | read hote | ||
| - | echo ############################# | ||
| - | echo | ||
| - | echo ### Pour l'aide tapez help ### | ||
| - | echo | ||
| - | while [ 1 ]; do # permet une boucle infinie | ||
| - | echo -n ""$login"@"$hote"$ " # qui s'arrête avec break | ||
| - | read reps | ||
| - | case $reps in | ||
| - | help | hlp ) | ||
| - | echo A propos de TS --> about | ||
| - | echo ls --> liste les fichiers | ||
| - | echo rm --> détruit un fichier (guidé) | ||
| - | echo rmd --> efface un dossier (guidé) | ||
| - | echo noyau --> version du noyau linux | ||
| - | echo connect --> savoir qui est c'est dernièrement connecté;; | ||
| - | ls ) | ||
| - | ls -la;; | ||
| - | rm ) | ||
| - | echo -n Quel fichier voulez-vous effacer : | ||
| - | read eff | ||
| - | rm -f $eff;; | ||
| - | rmd | rmdir ) | ||
| - | echo -n Quel répertoire voulez-vous effacer : | ||
| - | read eff | ||
| - | rm -r $eff;; | ||
| - | noyau | "uname -r" ) | ||
| - | uname -r;; | ||
| - | connect ) | ||
| - | last;; | ||
| - | about | --v | vers ) | ||
| - | echo Script simple pour l'initiation aux scripts shell;; | ||
| - | quit | "exit" ) | ||
| - | echo Au revoir!! | ||
| - | break;; | ||
| - | * ) | ||
| - | echo Commande inconnue;; | ||
| - | esac | ||
| - | done | ||
| - | exit 0 | ||
| - | |||
| - | ==Remarque== | ||
| - | |||
| - | Comme vous l'avez remarqué, l'indentation a une place importante dans | ||
| - | ce programme. En effet, celui-ci est plus lisible et cela évite aussi de faire | ||
| - | des erreurs. C'est pourquoi je vous recommande de bien structurer le code que vous | ||
| - | écrivez. | ||
| - | |||
| - | ====La commande for==== | ||
| - | L'instruction `for` exécute ce qui est dans son bloc un nombre de fois prédéfini. Sa syntaxe est la suivante : | ||
| - | |||
| - | for variable in valeurs; do | ||
| - | instructions | ||
| - | done | ||
| - | |||
| - | Comme vous l'aurez sans doute remarqué, on assigne une valeur différente à //variable// à chaque itération. On peut aussi très facilement utiliser des fichiers comme "valeur". Rien ne vaut un exemple : | ||
| - | |||
| - | #!/bin/sh | ||
| - | for var in $(ls *.txt); do | ||
| - | echo $var | ||
| - | done | ||
| - | exit 0 | ||
| - | |||
| - | On peut voir une syntaxe un peu particulière : `$(ls *.txt)`. Ceci sert à | ||
| - | indiquer que ce qui est entre les parenthèses est une commande à exécuter. | ||
| - | |||
| - | On peut aussi utiliser | ||
| - | cette instruction simplement avec des nombres, cela permet de connaître le nombre d'itérations : | ||
| - | |||
| - | #!/bin/sh | ||
| - | for var in 1 2 3 4 5 6 7 8 9; do | ||
| - | echo $var | ||
| - | done | ||
| - | exit 0 | ||
| - | |||
| - | On peut très bien aussi utiliser d'autres types de variables, comme par exemple des chaînes de | ||
| - | caractères : | ||
| - | |||
| - | #!/bin/sh | ||
| - | for var in Ubuntu Breezy 5.10; do | ||
| - | echo $var | ||
| - | done | ||
| - | exit 0 | ||
| - | |||
| - | Il faut quand même faire attention au fait que //Ubuntu Breezy 5.10// est différent de //"Ubuntu Breezy 5.10"// dans ce cas. En effet, tous les mots placés entre "" sont considérés comme faisant partie de la même chaîne de caractères. Sans les "", sh considèrera qu'il y a une liste de trois chaînes de caractères. | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | ====Les fonctions==== | ||
| - | |||
| - | Les fonctions sont indispensables pour bien structurer un programme mais aussi pouvoir le simplifier, créer une tâche, la rappeler... Voici la syntaxe générale de 'déclaration' d'une fonction: | ||
| - | |||
| - | nom_fonction(){ | ||
| - | instructions | ||
| - | } | ||
| - | |||
| - | Cette partie ne fait rien en elle même, elle dit juste que quand on on appellera nom_fonction, elle fera instruction. Pour appeler une fonction (qui ne possède pas d'argument, voir plus loin) rien de plus simple: | ||
| - | |||
| - | nom_fonction | ||
| - | |||
| - | |||
| - | Rien ne vaut un petit exemple: | ||
| - | |||
| - | #!/bin/sh | ||
| - | |||
| - | #Definition de ma fonction | ||
| - | mafonction(){ | ||
| - | echo 'La liste des fichiers de ce répertoire' | ||
| - | ls -l | ||
| - | } | ||
| - | #fin de la définition de ma fonction | ||
| - | |||
| - | echo 'Vous allez voir la liste des fichiers de ce répertoire:' | ||
| - | mafonction #appel de ma fonction | ||
| - | exit 0 | ||
| - | | ||
| - | Comme vous l'avez sans doute remarqué, quand on appelle la fonction, on exécute simplement ce qu'on lui a défini au début, dans notre exemple, echo... et ls -l, on peut donc faire exécuter n'importe quoi à une fonction. | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | ==== Lien ==== | ||
| - | |||
| - | Pour ceux qui souhaitent aller plus loin dans la conception de script shell, je vous recommande ce cours de chez developpez.com : | ||
| - | http://marcg.developpez.com/ksh/ | ||
| - | |||
| - | Bash parameters and parameter expansions. En anglais mais contient de nombreux exemples concernant la gestion et l'analyse des paramètres : | ||
| - | http://www.ibm.com/developerworks/library/l-bash-parameters.html | ||
| - | |||
| - | ---- | ||
| - | //Contributeurs: Rédigé par [[utilisateurs:gapz|gapz]] et [[utilisateurs:gloubiboulga|gloubiboulga]]// | ||