[gpocentek ] Il y a un petit download à faire avant de commencer :
[gpocentek ] http://u-classroom.net/files/2009-07-10/shell/classroom-scripts.tar.bz2
[gpocentek ] à décompresser, ça vous donnera un dossier classroom-scripts qui contient tous les exemples du cours
[gpocentek ] ok pour commencer ?
[FLOZz ] vivi
[beware007 ] Ok
[mouradbk ] bonjour
[gpocentek ] Ce soir on va aborder des éléments plus proche de la programmation que la semaine dernière
[gpocentek ] == Bases ==
[gpocentek ] Résumé à son plus simple aspect, un script shell est la description d'une liste
[gpocentek ] de commandes à exécuter automatiquement. Mais il est possible de rendre
[gpocentek ] l'exécution de ces commandes intelligente, suivant des conditions, selon un
[gpocentek ] ensemble d'arguments donnés, suivant l'environnement, etc.
[gpocentek ] == Organisation d'un script ==
[gpocentek ] On va commencer avec l'exemple 01.sh
[gpocentek ] je suppose que vous avez tous un éditeur de texte à disposition ?
[gapz ] ed!
[FLOZz ] vim :p
[gpocentek ] cat fait l'affaire aussi pour le coup ;)
[beware007 ] j'ai word, c'est bon?
[Vaugirard ] Geany
[gpocentek ] beware007: notepad serait plus indiqué ;)
[FLOZz ] beware007, XD
[gpocentek ] Donc vous avez le fichier 01.sh sous les yeux
[gpocentek ] Le script se décompose en 3 parties :
[gpocentek ] * le "shebang". Cette ligne n'est pas nécessaire au script, mais est
[gpocentek ] nécessaire pour que le système sache quel interpréteur utiliser lors de
[gpocentek ] l'exécution. Dans notre cas l'interpréteur sera /bin/sh. Attention, le
[gpocentek ] shebang est utilisé lorsque le script est rendu exécutable (chmod +x), et
[gpocentek ] qu'il est appelé directement. Il est par exemple possible d'utiliser bash
[gpocentek ] plutôt que sh avec la commande suivante :
[gpocentek ] bash 01.sh
[gpocentek ] * la suite définit le véritable contenu du script (très simple dans cet
[gpocentek ] exemple)
[gpocentek ] * on termine en utilisant la commande 'exit' pour sortir du script avec le
[gpocentek ] code de retour indiqué. Cette commande n'est pas obligatoire, et le script
[gpocentek ] finira avec un code de retour de 0 si elle est omise, mais l'utiliser est
[gpocentek ] considéré une bonne pratique.
[gpocentek ] Pour exécuter ce script : chmod +x 01.sh ./01.sh
[gpocentek ] pardon...
[gpocentek ] chmod +x 01.sh
[gpocentek ] ./01.sh
[gpocentek ] Pour exécuter un script (ou binaire), le shell a besoin de connaître son
[gpocentek ] chemin. Si ce chemin n'est pas indiqué, le shell cherchera l'exécutable dans
[gpocentek ] les dossiers de la variable d'environnement PATH. Par conséquent utiliser la
[gpocentek ] commande '01.sh' sans le ./ impliquera une recherche d'un fichier 01.sh dans le
[gpocentek ] PATH (et a priori la recherche échouera).
[gpocentek ] Le chemin n'a pas besoin d'être absolu (complet depuis /, comme par exemple
[gpocentek ] /home/gauvain/dossier/script.sh), il peut être relatif. './01.sh' précise que
[gpocentek ] le script à exécuter est dans le dossier courant.
[gpocentek ] questions, remarques ?
[Vaugirard ] Quelle est la différence entre Bash et Sh ?
[beware007 ] Le "shebang" doit etre la 1ere ligne au sens (ligne 1) ou la premiere ligne que le shell rencontre?
[FLOZz ] Bash est plus mieux bien =)
[gpocentek ] Vaugirard: sh c'est le shell historique, et sur les systèmes récent sh est en fait un lien vers bash ou dash
[gpocentek ] c'est le nom générique en fait
[gpocentek ] beware007: à vérifier mais je pense qu'il doit être sur la première ligne
[gpocentek ] en tout cas il ne doit pas y avoir de commande avant
[beware007 ] je viens de teste a priori c'est la 2e option. Mais à verifier. Cela dit l'interet de commencer a la 40e ligne est nul
[gpocentek ] oui
[gpocentek ] vous avez pu exécuter le script sans problème ?
[gpocentek ] (j'espère que oui mais on ne sait jamais)
[beware007 ] yep
[illovae ] Vaugirard: généralement quand tu as un shebang sh, le script peut s'exécuter sur tout unix, qu'importe le shell, alors que shebang bash nécessite "bash" (ça dépend de ton code en fait)
[gpocentek ] ok, alors continuons
[gpocentek ] == Enchaînement des commandes ==
[gpocentek ] Chaque retour à la ligne signifie que la commande est terminée, et la prochaine
[gpocentek ] commande est listée sur la ligne suivante. Comme dans le terminal, il est
[gpocentek ] possible de mettre plusieurs commandes sur la même ligne grâce à ;, && et ||.
[gpocentek ] Le script 02.sh vous donne des exemples d'enchaînements de commandes.
[gpocentek ] Il est possible de saisir une longue commande sur plusieurs lignes en échappant
[gpocentek ] le caractère de fin de ligne (\ avant de taper ). Attention de ne pas
[gpocentek ] glisser un espace entre le backslash et \n (retour à la ligne).
[gpocentek ] je vous laisserai regarder chaque script à chaque fois
[gpocentek ] je préfère que vous voyez directement le code plutôt que de faire de longs discours
[gpocentek ] (pour les nouveaux arrivants : http://u-classroom.net/files/2009-07-10/shell/classroom-scripts.tar.bz2)
[gpocentek ] des questions particulières sur 02.sh ?
[Vaugirard ] C'est bon, pour l'instant
[beware007 ] non, c'est bon
[gpocentek ] ok je continue
[gpocentek ] == Interaction avec l'utilisateur ==
[gpocentek ] Très souvent un script a besoin d'informations apportées par l'utilisateur pour
[gpocentek ] exécuter telle ou telle action. Un moyen de les obtenir est d'interagir avec
[gpocentek ] l'utilisateur. La commande 'read' permet d'attendre la saisie de l'utilisateur
[gpocentek ] et de stocker son texte dans une variable. 03.sh utilise cette technique.
[gpocentek ] Dans cet exemple 'read' lit deux variables, NOM et PRENOM. Le caractère espace
[gpocentek ] définit où s'arrête la première chaîne de caractères.
[gpocentek ] Essayez de saisir différentes valeurs, par exemple :
[gpocentek ] sh 03.sh Bonneau Jean
[gpocentek ] sh 03.sh De La Lune Pierrot
[gpocentek ] Note : par défaut echo ajoute un caractère de fin de ligne lorsqu'il a affiché
[gpocentek ] ses arguments. L'option -n annule cet ajout.
[gpocentek ] je vous laisse vous amuser avec ça
[gpocentek ] le caractère espace a vraiment un rôle très fort dans les scripts
[gpocentek ] c'est pour ça que vous lirez souvent que les espaces dans les noms de fichier sous linux, c'est pas une bonne idée
[FLOZz ] et il casse les pied très fort des fois aussi ^^
[FLOZz ] rofl grillé
[gpocentek ] :)
[gpocentek ] vous avez pu tester différents arguments avec 03.sh ?
[Vaugirard ] Oui, avec un ou deux arguments, cela fonctionne toujours
[beware007 ] si je comprends bien : il prend pour 1er argument tout ce qui se trouve avant le 1er espace et comme 2e tout ce qui se trouve aprés ce 1er espace et ce meme s'il y a encore des espaces?
[gpocentek ] beware007: exactement
[beware007 ] Ouf ca me rassure :)
[beware007 ] merci
[gpocentek ] === Conditions et boucles ===
[gpocentek ] == test ==
[gpocentek ] Un élément important des scripts (et de tout langage de programmation) est la
[gpocentek ] possiblité de pouvoir faire des tests. Le shell offre plusieurs types de tests
[gpocentek ] comme :
[gpocentek ] * la comparaison de chaînes de caractères
[gpocentek ] * la comparaison de valeurs numériques
[gpocentek ] * l'existance et le type d'un fichier
[gpocentek ] * le code de retour d'une commande
[gpocentek ] Tous ces tests peuvent être combinés entre eux avec des opérateurs logiques
[gpocentek ] (ou/et).
[gpocentek ] La commande 'test' permet d'effectuer un de ces tests. Si l'expression qui lui
[gpocentek ] est passée en argument est vraie, alors test retourne 0 (succès). Sinon elle
[gpocentek ] retourne la code de retour de l'expression. Quelques exemples de tests (rappel,
[gpocentek ] afficher le code de retour se fait grâce à 'echo $?') :
[gpocentek ] * comparaison de chaines de caractères :
[gpocentek ] test "$X" = "$Y"
[gpocentek ] Le premier test vérifie l'égalité des 2 chaînes, le second leur différence.
[gpocentek ] * comparaison de valeurs numériques :
[gpocentek ] test 1 -gt 3
[gpocentek ] -gt signifie 'greater than' (plus grand que), et -ne 'not equal' (non égal).
[gpocentek ] * test sur les fichier
[gpocentek ] test -e /bin
[gpocentek ] -e teste si le chemin existe, -d si c'est un dossier, -f si c'est un fichier.
[gpocentek ] * opérateurs logiques
[gpocentek ] test 2 -gt 0 -a 5 -lt 10
[gpocentek ] -a signifie 'et', les 2 conditions doivent être remplies pour que test retourne
[gpocentek ] 0. -o signifie 'ou', si l'une des 2 conditions est remplie alors test
[gpocentek ] retournera 0.
[gpocentek ] 'man test' vous donnera la liste exhaustive des tests existants.
[gpocentek ] c'est plus théorique que pratique cette section mais il y aura des exemples justes après
[gpocentek ] des questions ?
[FLOZz ] oui
[FLOZz ] pourquoi tu ne parle pas de la commande [ en plus de test ?
[gpocentek ] parce que c'est prévu plus loin ;)
[FiFouille ] FLOZz: parce que c'est tip top pareil et que ça veint au point 07.sh :p
[FLOZz ] ok :X
[Vaugirard ] Est-ce que l'on peut écrire test 2 -gt 0 -a 5 -lt 10 -a 2 -gt 4 -a 5 -lt 8 ?
[gpocentek ] oui
[gpocentek ] on peut enchaîner autant de tests qu'on veut
[gpocentek ] ok pour ça ?
[beware007 ] ok
[gpocentek ] on va entrer dans les exemples maintenant
[Vaugirard ] Oui
[gpocentek ] == if/elif/else/fi ==
[gpocentek ] Il est bien entendu intéressant de pouvoir faire agir le script selon le
[gpocentek ] résultat du test. Pour ce on utilise 'if'. L'exemple 04.sh vous illustre son
[gpocentek ] utilisation.
[gpocentek ] essayez avec une valeur plus grande et une valeur plus petite que 10 pour voir l'effet ;)
[gpocentek ] Notez que la condition est terminée par un ; et suivie de 'then'. Ce 'then' est
[gpocentek ] obligatoire. Sans lui le shell ne comprend pas que la description de la
[gpocentek ] condition s'arrête là. Il est également possible de placer 'then' sur la ligne
[gpocentek ] suivante, auquel cas le ; n'est pas obligatoire (cf 05.sh). 'then' est
[gpocentek ] nécessaire après 'if' ou 'elif', il ne doit pas être utilisé après else.
[gpocentek ] N'oubliez pas de signifier au shell que la test est fini grâce à 'fi'
[beware007 ] Zut, j'avais une question sur les test. Est il possible de les combiner du genre : and {foor or bar}
[gpocentek ] (je teste avant de dire des bêtises)
[FLOZz ] beware007, test xxx && test yyy
[beware007 ] je trouve ca moins pratique :) (enfin avis perso)
[gpocentek ] en fait non tu ne peux pas combiner directement
[gpocentek ] FiFouille: tu confirmes ?
[gpocentek ] en attendant ça vous parait clair la syntaxe de if/else/etc ?
[FiFouille ] gpocentek: normalement tu peux faire des groupements avec les ( ), par contre ça interagit mal avec les subshells etc
[FLOZz ] test $var == 2 || test $var == 3
[FLOZz ] ($var = 3 ou 3)
[gpocentek ] FiFouille: mais ça c'est pas possible 'test 0 -lt 1 -a (1 -gt 2 -o 1 -lt 2)'
[FLOZz ] 2 ou 3 ^^'
[Vaugirard ] Le script ne fonctionne pas toujours : j'ai saisi 999999999999999999999999999999 et il me répond 'Pas très sympa" alors que c'est supérieur à 10.
[FiFouille ] gpocentek: en escapant les () \( et \); je dirais que oui
[gpocentek ] gauvain@zero:~/classroom-scripts$ test 0 -lt 1 -a \(1 -gt 2 -o 1 -lt 2\)
[gpocentek ] bash: test: (1: integer expression expected
[gpocentek ] donc il faut bien combiner plusieurs appels de test
[beware007 ] Ok, merci pour vos réponses
[FiFouille ] test 1 -gt 0 -a \( 1 -gt 2 -o 1 -gt 0 \)
[gpocentek ] on continue ou vous voulez d'autres précisions ?
[Vaugirard ] On continue !
[beware007 ] Ok, merci pour vos réponses
[gpocentek ] merci FiFouille :)
[FiFouille ] \( il vaut mieux \) ;)
[gpocentek ] == case/esac ==
[gpocentek ] Il est également possible d'utiliser case/esac pour tester une valeur, comme
[gpocentek ] dans l'exemple 06.sh. Sa syntaxe est :
[gpocentek ] case $variable in
[gpocentek ] x)
[gpocentek ] echo "Erreur"
[gpocentek ] exit 1
[gpocentek ] ;;
[gpocentek ] esac
[gpocentek ] Les tests de comparaison entre $variable et chaque valeur sont faits dans
[gpocentek ] l'ordre. Le wildcard (*) peut être utilisé dans toutes les valeurs (comme dans
[gpocentek ] l'exemple 06.sh, où l'on teste uniquement la présence du caractère - comme
[gpocentek ] premier caractère). Les ;; précisent qu'on arrête de parcourir les autres
[gpocentek ] valeurs proposées.
[gpocentek ] En général la dernière valeur à tester est *, qui correspond à n'importe quelle
[gpocentek ] valeur existante. Si toutes les autres comparaisons ont échoué, alors une
[gpocentek ] action par défaut est initiée (par exemple l'affichage d'un message d'erreur
[gpocentek ] puis la sortie du script).
[gpocentek ] case/esac est très utile quand vous avez une liste finie de valeurs à tester
[beware007 ] ca simplifie l'ecriture en tout cas
[gpocentek ] ça clarifie les choses, mais ça ne peut pas remplacer tous les if/else
[gpocentek ] == Autre syntaxe de 'test' ==
[gpocentek ] Il existe une autre syntaxe pour 'test', beaucoup plus utilisée. Il s'agit du
[gpocentek ] couple [ ]. [ n'est *pas* un caractère spécial mais bien une commande, et doit
[gpocentek ] être traité comme tel. Une erreur courante dans son utilisation est l'omission
[gpocentek ] d'un espace entre [ et l'expression qui suit. En effet, l'expression est un
[gpocentek ] argument de la commande [, et doit donc être séparé par un espace.
[gpocentek ] Le dernier argument de [ doit être ] (précédé d'un espace puisqu'il s'agit d'un
[gpocentek ] argument).
[gpocentek ] L'exemple 05.sh avec le changement de syntaxe devient 07.sh.
[gpocentek ] l'oubli de l'espace après [ ça m'a fait perdre pas mal de temps
[gpocentek ] j'espère que je vous en ferai gagner en précisant tout ça :)
[FLOZz ] gpocentek, t'es pas le seul ^^
[gpocentek ] est-ce que cette syntaxe vous parait claire ?
[FLOZz ] on le vois pas toujours quand on l'ouble :(
[Vaugirard ] Pour la commande case, on a vu que l'on peut utiliser "*" comme joker. Peut(on utiliser aussi "?" ?
[gpocentek ] Vaugirard: oui
[Vaugirard ] C'est pas mal, alors !
[gpocentek ] tu peux utiliser toutes les modifications de syntaxe
[gpocentek ] j'exagère un peu en fait
[gpocentek ] tu peux utiliser ce que tu utilise dans ton shell pour des correspondaces multiples
[gpocentek ] tu peux aussi utiliser quelque chose comme [0-9]* pour gérer les valeurs commençant par un chiffre
[FLOZz ] ra{r,t}) ça marche ?
[gpocentek ] avec du bash je pense
[gpocentek ] la syntaxe {x,y} c'est du bash, c'est pas POSIX
[FLOZz ] y i know ^^
[gpocentek ] avec dash, ash ou autre ça ne fonctionnerait pas, ou pas comme tu le souhaites
[gpocentek ] comme ça tout le monde le sait maintenant ;)
[FLOZz ] je connais pas trop les autres shell :/
[FLOZz ] faudrait que j'essaie un de ces jours
[gpocentek ] d'autres question sur les tests avant qu'on passe aux boucles ?
[gpocentek ] je continue alors
[gpocentek ] == Boucles ==
[gpocentek ] = while =
[gpocentek ] Une boucle 'while' permet de répéter la même chose tant qu'une condition est
[gpocentek ] vérifiée. Des données peuvent bien sûr être modifiées durant l'exécution de
[gpocentek ] cette boucle. L'exemple 08.sh est une implémentation d'un jeu dans lequel on
[gpocentek ] doit deviner un nombre choisi au hasard.
[gpocentek ] Quelques remarques sur ce script :
[gpocentek ] * $$ est une variable spéciale qui contient le PID (Process ID) du script
[gpocentek ] * on peut faire des calculs grâce à $(( le calcul ))
[gpocentek ] l'écriture (pas besoin de if/then/fi pour 1 unique action)
[gpocentek ] De la même manière que 'if' nécessite un 'then', 'while' nécessite un 'do'. Et
[gpocentek ] la fin de la boucle 'while' est notifiée grâce à 'done'.
[gpocentek ] je vous laisse deviner le nombre et regarder le script ;)
[FiFouille ] gpocentek: moi je sais, suffit de rien mettre :p
[gpocentek ] FiFouille: ou de faire un 'ps' ;)
[Vaugirard ] Il y a déjà des tricheurs...
[gpocentek ] le script sert surtout à montrer la boucle while, afin d'être un vrai jeu :)
[gpocentek ] s/afin/avant/
[gpocentek ] est-ce que la syntaxe du while est comprise ?
[gpocentek ] est-ce que vous avez des questions ?
[FLOZz ] pas vraiment aléatoire
[FLOZz ] $RANDOM aurais été mieux non ?
[Vaugirard ] Et si on deux conditions reliées par AND ou OR, on l'écrit comment ?
[gpocentek ] l'un ou l'autre fonctionnent très bien pour ce type d'exemple
[FLOZz ] ouai c'est vrai ^^
[FLOZz ] au fait
[gpocentek ] Vaugirard: while [ condition 1 ] && [ condition 2 ]; do
[Vaugirard ] Merci.
[gpocentek ] même chose avec || pour or
[FLOZz ] le $RANDOM il va de 0 à combien déjà ? :/
[gpocentek ] aucune idée
[gpocentek ] Vaugirard: tu peux aussi utiliser while [ condition 1 -a condition 2 ]; do
[FiFouille ] 32767 je pense
[FLOZz ] 32767 ouai je viens de relir le man bash
[gpocentek ] beware007: ça va pour toi ?
[gpocentek ] (on a perdu beware007)
[gpocentek ] je vais continuer avec for
[gpocentek ] = for =
[gpocentek ] 'for' permet d'exécuter un ensemble de commandes en utilisant un nombre finis
[gpocentek ] de valeurs, comme dans l'exemple 09.sh. Cet exemple lit une liste de mots puis
[gpocentek ] inverse cette liste et l'affiche.
[gpocentek ] 'for' utilise également 'do' et 'done' pour encadrer les commandes à boucler.
[gpocentek ] je vous laisse regarder 09.sh avant d'aborder une question épineuse
[gpocentek ] je n'ai pas précisé mais la liste de mot est encore et toujours séparée par des espaces
[gpocentek ] La gestion des valeurs à utiliser avec for est l'occasion d'aborder
[gpocentek ] l'utilisation des "" et des ''. L'exemple 10.sh exécute 3 fois la même boucle
[gpocentek ] 'for' sur la même variable, mais l'utilisation (ou pas) de quotes simples et
[gpocentek ] doubles n'a pas le même effet :
[gpocentek ] * sans rien autour de $LISTE, les espaces sont interprétés comme de réels
[gpocentek ] séparateurs d'arguments et les 3 mots sont bien distincts
[gpocentek ] * avec "", $LISTE devient un argument unique, et donc la boucle for n'est
[gpocentek ] parcourue qu'une seul fois
[gpocentek ] * avec '', $LISTE est également un argument unique, de plus l'expansion du
[gpocentek ] shell n'est pas appliquée.
[gpocentek ] Cette notion d'interprétation des arguments et des variables suivant les "" et
[gpocentek ] '' peut être la source de nombreuses erreurs et incompréhensions si elle n'est
[gpocentek ] pas assimilée. Elle est valide dans tous les cas d'utilisation de variables,
[gpocentek ] pas uniquement avec for.
[gpocentek ] (j'avoue que ça me donne encore des migraines ce truc)
[gpocentek ] est-ce que c'est clair la différence de résultat suivant que la variable est incluse entre "", '' ou rien ?
[FLOZz ] j'ai abandoner for pour lire les argument passés aux script
[Vaugirard ] J'ai aussi entendu parler des apostrophes simples inversées (`), que signifient-elles ici ?
[gpocentek ] Vaugirard: les `` exécutent une commande
[FLOZz ] c'est pour faire des substitution les ``
[gpocentek ] (cf le cours de la semaine dernière, c'est expliqué dedans)
[gpocentek ] si on a foo=ls
[gpocentek ] `$foo` exécutera la commande 'ls'
[gpocentek ] on continue ?
[FLOZz ] ata
[FLOZz ] $foo
[FLOZz ] donne execute déjà ls
[FLOZz ] ^^
[gpocentek ] oui pardon je mixe tout là
[gpocentek ] `$foo` exécutera le premier fichier listé par 'ls' en fait
[FLOZz ] ce serais plutôt foo=`ls`
*FLOZz trouve que gpocentek tape plus vite que lui au clavier :(
[gpocentek ] je vous laisse expérimenter tout ça ;)
[gpocentek ] je vous propose de passer à la suite, et de revenir sur certains points tout à l'heure
[gpocentek ] === Gestion des arguments ===
[gpocentek ] Les scripts sont souvents écrits pour automatiser une tâche. L'interaction avec
[gpocentek ] l'utilisateur n'est pas souhaitée dans ce cas, et la méthode qui s'impose pour
[gpocentek ] donner des informations au script est de lui passer des arguments.
[gpocentek ] Les arguments passés au script via la ligne de commande sont stockés dans des
[gpocentek ] variables spéciales :
[gpocentek ] * $@ : liste des arguments passés
[gpocentek ] * $1, $2... : 1er argument, 2ème argument...
[gpocentek ] L'exemple 11.sh utilise ces variables spéciales, et l'exemple 12.sh en montre
[gpocentek ] une utilisation un peu plus concrète (bien que très simple).
[FLOZz ] c'est quoi la différence entre $@ et $* ?
[gpocentek ] très bonne question
[gpocentek ] dont je n'ai pas la réponse
[FLOZz ] lol
[gpocentek ] je ferai des recherches mais effectivement le résultat semble être le même
[FiFouille ] ./11.sh foo bar "baz quux"
[FiFouille ] avec $* tu aurais foo baz baz quux
[FiFouille ] avec $@ "foo" "bar" "baz quux"
[FLOZz ] le livre que j'ai entre les patte me sort une différence mais je comprend pas :/
[FLOZz ] $* : tous les paramètres
[FLOZz ] $@ idem (mais "$@" eq. à "$1" "$2" ...)
[FiFouille ] d'aileurs dans l'exemple 11 il serait recommandé de mettre for i in "$@"
[FLOZz ] faudra que je teste
[FiFouille ] pour éviter les blagues quand on appelle avec la forme 11.sh foo bar 'baz qux'
[gpocentek ] bien vu
[FiFouille ] FLOZz: on en reparle après si tu veux ;)
[FLOZz ] ok :p
[gpocentek ] merci pour les précisions FiFouille
[gpocentek ] (j'aurais dû te laisser faire le cours ;) )
[gpocentek ] La commande 'getopts' permet de gérer assez simplement les arguments du type
[gpocentek ] -x, -y, etc. Elle prend 2 arguments. Le premier est la liste des switchs, le
[gpocentek ] second le nom de la variable dans laquelle est temporairement stocké les
[gpocentek ] informations de l'argument. 'getopts' n'a de sens qu'utilisé dans une boucle
[gpocentek ] qui parcours tous les arguments de la ligne de commande. Voir l'exemple 13.sh,
[gpocentek ] avec quelques remarques :
[gpocentek ] * un switch suivi de ':' précise à getopts qu'un valeur est attendue à la
[gpocentek ] suite ('-x /chemin/vers/fichier' par exemple)
[gpocentek ] * l'argument est alors stocké dans la variable $OPTARG
[gpocentek ] * la variable $OPTIND contient l'indice du prochain argument à traiter. Au
[gpocentek ] sortir de la boucle while il est possible d'accéder à d'éventuels arguments
[gpocentek ] additionnels en utilisant cette valeur. La commande 'shift' permet de
[gpocentek ] supprimer les X premiers arguments de la liste, et 'réinitialiser' le
[gpocentek ] compteur (un argument $4 devient $1 grâce à 'shift 3').
[gpocentek ] essayez par exemple 'sh 13.sh -a foo -b foo2 bar'
[gpocentek ] je ne suis pas sûr d'être clair sur le sens de la variable $OPTIND
[gpocentek ] je peux tenter une reformulation au besoin
[gpocentek ] est-ce que j'ai perdu tout le monde ?
[FLOZz ] non
[FLOZz ] je suis encore là ;)
[Vaugirard ] Pas encore
[beware007 ] non je suis toujours
[gpocentek ] je pense que l'exemple est plus parlant que ce que je raconte en fait :s
*FiFouille vient de décrouvrir l'existence de OPTIND
[gpocentek ] \o/
[gpocentek ] on continue ?
[Vaugirard ] Oui
[gpocentek ] ok
[gpocentek ] === Organisation ===
[gpocentek ] Quand un script devient long, il est intéressant de pouvoir l'organiser. Deux
[gpocentek ] éléments sont là pour ça : 'source' et 'function'.
[gpocentek ] == source ==
[gpocentek ] Utiliser '.' (source) permet d'inclure le contenu d'un autre fichier shell
[gpocentek ] dans le script courant. Cette solution est par exemple utile pour inclure des
[gpocentek ] assignations de variables depuis en fichier de configuration, comme dans
[gpocentek ] l'exemple 14.sh. L'exécution des instructions se fait à l'endroit même ou le
[gpocentek ] script est inclus. Celà signifie que des variables peuvent être réassignées par
[gpocentek ] le fichier inclus.
[gpocentek ] je pense que c'est assez simple ça, questions ?
[beware007 ] nop
[gpocentek ] au passage, la commande 'source' en toutes lettres n'est pas POSIX
[FLOZz ] beware007, tu fais de l'asm ?
[Vaugirard ] On peut mettre n'importe quel type d'instruction dans le fichier .cfg ?
[gpocentek ] elle est implémentée sous bash par exemple mais pas dans tous les shells
[FLOZz ] gpocentek, le point l'est lui ?
[gpocentek ] Vaugirard: oui
[beware007 ] non FLOZz
[gpocentek ] FLOZz: le point est POSIX
[FLOZz ] ok je retiens
[Vaugirard ] L'extension .cfg est facultative, je pense ?
[gpocentek ] Vaugirard: tout à fait, ça aurait pu être .doc ou .scoubidou du moment que c'est une lanage shell à l'intérieur
[gpocentek ] du langage*
[beware007 ] FLOZz : en fait c'est quoi l'asm?
[FLOZz ] beware007, abréviation de assembler (un langage de très bas niveau)
[gpocentek ] je continue sur l'organisation avec les fonctions
[gpocentek ] == function ==
[gpocentek ] Une fonction peut être vue comme une commande. L'intérêt des fonctions est
[gpocentek ] qu'elles peuvent être définies par l'auteur du script.
[gpocentek ] La définition d'une fonction se fait grâce la syntaxe suivante :
[gpocentek ] function nom_de_function () { commande; commande; commande }
[gpocentek ] La fonction peut recevoir des arguments, qui peuvent être traités de la même
[gpocentek ] manière que les arguments passés au scripts. Les variables $#, $@, $X... sont
[gpocentek ] alors *locales* à la fonction. Nous reviendrons sur cette notion dans le
[gpocentek ] prochain paragraphe.
[gpocentek ] Pour savoir si une fonction a fonctionné comme prévu, elle peut egalement
[gpocentek ] à l'intérieur d'une fonction), c'est la commande 'return' qui est utilisée.
[gpocentek ] L'exemple 15.sh est une réécriture du jeu de devinette de nombre en utilisant
[gpocentek ] une fonction.
[gpocentek ] Note : la commande 'break' permet de sortir d'une boucle 'while' ou 'for'. La
[gpocentek ] commande 'continue' permet au contraire de passer à l'itération suivante de la
[gpocentek ] boucle, sans finir celle en cours.
[beware007 ] FLOZz > alors oui j'en ai un peu fait. Assembleur pour motorola 68HC11 :)
[beware007 ] Cool, je savais pas que les fonctions etaient possibles sous bash. Ca peut etre trés pratique
[FiFouille ] gpocentek: c'est POSIX function foo() ?
[gpocentek ] erf
[gpocentek ] 'function' ne doit pas être là, j'ai fait un mélange
[gpocentek ] la définition d'une fonction c'est simplement :
[gpocentek ] nom_de_function () { commande; commande; commande }
[FLOZz ] gpocentek, je me disais aussi ^^
[gpocentek ] désolé pour la faute
[FiFouille ] et selon cette syntaxe, il manque un ; après le dernier 'commande' ... (je sais, je pinaille encore)
[gpocentek ] indeed, c'est pour voir si tu suis
[gpocentek ] à part ces erreurs de syntaxe, est-ce que c'est compris pour tout le monde cette notion de fonction ?
[Vaugirard ] Oui.
[RockyRoad ] yep :)
[gpocentek ] good :)
[gpocentek ] == Portée des variables ==
[gpocentek ] En shell les variables sont globales, c'est à dire accessibles depuis n'importe
[gpocentek ] quel endroit du script, y compris depuis les fichiers sourcés. Dans des projets
[gpocentek ] d'une certaine envergure, il est possible qu'une fonction utilise une variable
[gpocentek ] définie ailleurs dans un but tout à fait différent, et par conséquent perturbe
[gpocentek ] l'exécution du script. Pour éviter ce problème, il est possible de définir une
[gpocentek ] variable comme locale à une fonction grâce au mot clé 'local' :
[gpocentek ] local I=0
[gpocentek ] Une exception à cette règle de globalité est le caractère local des arguments
[gpocentek ] dans les fonctions. $1 correspond à l'argument 1 de la ligne de commande en
[gpocentek ] dehors d'une fonction, mais au premier argument passé à la fonction à
[gpocentek ] l'intérieur de celle ci (même si cet argument est vide).
[gpocentek ] est-ce que c'est ok ça ?
[RockyRoad ] compare() est definie sans argument ...
[RockyRoad ] et utilise $1 et $2
[gpocentek ] c'est surtout important si vous utilisez d'autres langages de programmation om les variables sont locales par défaut en général
[gpocentek ] RockyRoad: oui, on n'a pas besoin de définir les arguments
[RockyRoad ] ok. merci
[gpocentek ] on n'a pas a les lister dans la définition de la fonction plus précisément
[gpocentek ] à les lister*
*gpocentek fatigue
[FiFouille ] gpocentek: plus que 4, courage ;)
[gpocentek ] :)
[Vaugirard ] Après, il y a les questions.
[gpocentek ] attaquons le dernier paragraphe ;)
*RockyRoad aimerais bien ne pas faire plus de fautes de frappe que gpocentek
[gpocentek ] la dernière section plutôt
[gpocentek ] === Manipulation des flux ===
[gpocentek ] Nous avons vu au cours précédent comment rediriger des flux depuis stdout et
[gpocentek ] stderr vers un fichier. Il est aussi intéressant de pouvoir automatiser la
[gpocentek ] lecture depuis stdin ou un fichier.
[gpocentek ] == << ==
[gpocentek ] Lorsque 'cat' est utilisé sans argument, il lit les information à écrire depuis
[gpocentek ] stdin. A chaque fois qu'un retour chariot est reçu, la "phrase" qui vient d'être
[gpocentek ] saisie est affichée. On peut changer ce comportement en spécifiant à cat une
[gpocentek ] chaîne de caractère qui marquera la saisie. C'est l'opérateur '<<' qui se
[gpocentek ] chargera d'indiquer le changement :
[gpocentek ] $ cat << EOF
[gpocentek ] > bla
[gpocentek ] > EOF
[gpocentek ] bla
[gpocentek ] bli
[gpocentek ] blu
[gpocentek ] Attention, '<<' n'est *pas* lié à 'cat', il s'agit bien d'un outil du shell, qui est
[gpocentek ] utilisable avec tous les outils sachant lire et utiliser stdin. Voici un autre
[gpocentek ] exemple (avec grep) :
[gpocentek ] $ grep foo << EOF
[gpocentek ] > scoubidou
[gpocentek ] foobar
[gpocentek ] EOF signifie End Of File est est généralement utilisé pour notifier la fin du
[gpocentek ] texte. Cependant vous pouvez utiliser n'importe quelle chaîne de caractères.
[gpocentek ] Il est possible dans un script d'indiquer le texte à écrire directement, sans
[gpocentek ] devoir le saisir dans la console. C'est ce qui est fait dans l'exemple 16.sh.
[gpocentek ] Le script 17.sh fait exactement la même chose mais écrit dans un fichier 17.txt
[gpocentek ] au lieu d'écrire sur stdout.
[gpocentek ] exécutez le 17.sh, 17.txt qu'il génère sera utilisé après ;)
[gpocentek ] j'ai utilisé > pour écrire dans le fichier, mais vous pouvez également utiliser >> pour concaténer
[RockyRoad ] 'cat < 17.txt' marche aussi
[gpocentek ] oui
[gpocentek ] question de préférence pour choisir l'ordre
[gpocentek ] == < ==
[gpocentek ] '<' agit de la même manière que '<<', mais au lieu de lire stdin, il lit le
[gpocentek ] fichier dont le nom est passé en argument (exemple 18.sh).
[gpocentek ] == Utilisation avec while ==
[gpocentek ] Utiliser une boucle pour la lecture sur chaque ligne d'un fichier est donc aisé
[gpocentek ] grâce à '<', read et while. L'exemple 19.sh utilise ces éléments pour lister tous
[gpocentek ] les utilisateurs connus du système.
[gpocentek ] Notez que l'utilisation du '<' se fait au niveau du 'done', pas au niveau du 'do'
[gpocentek ] (donc à la fin de la description de la boucle).
[gpocentek ] des questions sur < et << ?
[FiFouille ] gpocentek: je suppose que <( foo ) c'est pas POSIX
[gpocentek ] FiFouille: jamais utilisé, je saurais pas te dire
[gpocentek ] je voulais aborder un dernier point avant la fin de la session, la gestion des erreurs
[gpocentek ] et après j'essaierai de répondre aux questions en tous genres ;)
[gpocentek ] === Gestion des erreurs ===
[gpocentek ] Si une commande échoue lors de l'exécution d'un script, le script lui même
[gpocentek ] n'échouera pas. Une erreur dans le script peut facilement devenir
[gpocentek ] catastrophique. Imaginons que vous fassiez confiance à un programme ou une
[gpocentek ] fonction pour retourner le chemin D=un/dossier/a/effacer, puis que vous
[gpocentek ] utilisiez 'rm -rf' pour effacer $HOME/$D. Que se passe-t-il si la commande
[gpocentek ] échoue et que D est vide ? Votre dossier personnel est effacé.
[gpocentek ] Pour éviter ce genre de problème, il est vivement conseillé de tester la
[gpocentek ] validité des variables que vous utilisez. Par exemple :
[gpocentek ] [ -n "$D" ] && rm -rf $HOME/$D
[gpocentek ] De même, vérifier le code de retour des fonctions et applications appelées est
[gpocentek ] généralement une bonne idée.
[gpocentek ] La commande 'set' vous permet de définir certaines options de l'environnement
[gpocentek ] d'exécution du shell. 'set -e' permettra d'arrêter le script si une erreur
[gpocentek ] survient pendant cette exécution. À titre d'exemple, cette configuration est
[gpocentek ] obligatoire lors de l'exécution des script de pré/post-installation des paquets
[gpocentek ] debian.
[gpocentek ] L'option 'set -x' active quand à elle un pseudo mode de debug. Toutes les
[gpocentek ] actions faites par le script seront détaillées dans la console.
[gpocentek ] Pour désactiver une option il suffit d'utiliser 'set +option' (par exemple 'set +x' ou 'set +e').
[gpocentek ] et voilà pour le cours de ce soir...
[RockyRoad ] Super bien fait gpocentek :)
[gpocentek ] merci :)
[RockyRoad ] utile concis et tout ...
[Vaugirard ] Très bien, mais il y a des questions !
[gpocentek ] le cours a pas la prétention de couvrir tous les aspects de scripting shell, c'est trop vaste
[gpocentek ] mais avec ça vous avez de bonnes bases pour vous y mettre je pense
[FiFouille ] man bash | wc -l
[FiFouille ] 4471
[FiFouille ] ... je confirme ;)
[gpocentek ] Vaugirard: je peux essayer de répondre ;)
[Vaugirard ] Comment faire du pas à pas pour déboguer un script ?
[FLOZz ] Question : es ce que c'est POSIX ça : « var=/home/foobar/1337 ; echo ${var##*/} »
[Vaugirard ] Pour les boucles, existe-t-il des instructions telles que "repeat" ou "loop" pour faire le test à la fin ou au milieu ?
[gpocentek ] Vaugirard: l'option set -x est un bon début pour le debug
[RockyRoad ] Une petite question sur ';' :
[RockyRoad ] On n'a pas le droit de mettre un point-virgule après 'then', mais pourtant, un saut de ligne passe bien. pourquoi?
[gpocentek ] doucement, doucement ^^
[gpocentek ] FLOZz: oui c'est POSIX
[FiFouille ] RockyRoad: le ; est un séparateur d'instruction, le retour à la ligne, c'est selon le contexte
[FLOZz ] cool :p
[gpocentek ] Vaugirard: repeat et loop je pense pas que ça existe
[gpocentek ] jamais vu en tout cas
[FLOZz ] par ce que je dois reconnaître que c'est très pratique ^^
[gpocentek ] FLOZz: il y a une méthode que j'apprécie pour tester la validité POSIX
[gpocentek ] essayer les commandes dans un shell dash :)
[gpocentek ] si tu est sur debian/ubuntu c'est installé par défaut
[gpocentek ] es*
[FLOZz ] gpocentek, Dash il implémente la norme POSIX à la lettre sans rien ajouter ?
[gpocentek ] c'est son but
[FLOZz ] gpocentek, OK intéressant... merci pour l'info !!! :p
[gpocentek ] Description: POSIX-compliant shell The Debian Almquist Shell (dash) is a lightweight POSIX-compliant shell derived from ash.
[RockyRoad ] FiFouille: tu veux dire que le saut de ligne est lu dans le contexte de l'instruction composée ?
[FiFouille ] checkbashisms du package devscripts c'est marrant aussi
[FiFouille ] RockyRoad: le shell s'attend à avoir une commande à la suite de then, donc un espace puis la commande ou un retour à la ligne puis la commande c'est pareil pour lui
[FiFouille ] par contre à la suite de ton if [ cond ] il sait pas s'il va trouver une autre condition/test ou s'il faut considérer que c'est la suite logique avec then ...
[FiFouille ] d'ailleurs si tu spécifies pas de commande après then le shell va pas trop apprécier
[FiFouille ] if [ 1 -eq 1 ]; then ; fi # par exemple
[RockyRoad ] le saut de ligne est un espace ordinaire apres then, c'est ça ?
[FLOZz ] gpocentek, dans un paquet deb vaut-il mieux utiliser sh, bash ?
[FiFouille ] oui
[gpocentek ] effectivement çà a l'air d'être interprété commça
[gpocentek ] FLOZz: les maintainers scripts dans un paquet debian utilisent sh, qui par défaut pointe sur dash
[FLOZz ] ok
[gpocentek ] c'est possible de les faire utiliser mais c'est pas très conseillé, et pas très policy compliant
[gpocentek ] utiliser bash*