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 28/11/2007, 00:53] 152.77.24.38 |
— (Version actuelle) | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | {{tag>Programmation développement}} | ||
- | ---- | ||
- | ======Introduction aux scripts shell====== | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== Présentation ===== | ||
- | |||
- | Un script shell est un fichier ou est écrit une ou plusieurs commandes qui sont exécuter de manier séquentielle, dans le plus simple des cas ligne par ligne. | ||
- | Ces commandes ou ces codes shells appellent plusieurs fonction plus ou moin complexe et permette d'obtenir plusieurs résultats fonction de la commande utiliser. | ||
- | |||
- | |||
- | === Pour faire un script intelligemment il faut respecter ces conditions: === | ||
- | |||
- | * Des vérifications approfondie doivent être faire sur TOUTES les commandes utilisé. | ||
- | * Des commentaires doivent pulluler sinon le script devient bien trop transparent, chaque étapes doivent être suivit d'un "echo <voici ce que je fais>" particulièrement utile notamment lors de débuggage. | ||
- | * Lors d'une mise a jour, un fils de discussion doit être préciser pour les bugs éventuels. | ||
- | * Avertir les utilisateurs les dégâts que peut causer les commandes utiliser. | ||
- | |||
- | Evidement ces conseils sont utile au débutant... | ||
- | <note tip>Astuce: Le plus important dans tout programme est l'algorithme utilisé</note> | ||
- | Exemple: | ||
- | Supposons que avez une base de donné, 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 bleu | ||
- | ou | ||
- | - calculer le nombre d'éléphant total - nombre d'éléphant blanc | ||
- | |||
- | 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 ^ | ||
- | | 0 ou 0 | 0 | | ||
- | | 0 ou 1 | 1 | | ||
- | | 1 ou 0 | 1 | | ||
- | | 1 ou 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 ^ | ||
- | | 0 et 0 | 0 | | ||
- | | 0 et 1 | 0 | | ||
- | | 1 et 0 | 0 | | ||
- | | 1 et 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 au milieu avec cette syntaxe zarbi ! | ||
- | 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]]// |