Projet

Général

Profil

Petit precis de shell » Historique » Version 19

Julien Enselme, 12/08/2013 18:42
Les redirections de flux : rédaction

1 1 Julien Enselme
Le shell est un langage assez particulier qu'on ne connait pas forcément en arrivant à centrale et qu'on a pas forcément l'occasion de beaucoup pratiquer. Le but de ce document est de rappeler les quelques bases du langage et de fournir quelques solutions standard à des problèmes courants afin que le nouveau membre du club Drupal ne soit pas désemparé et puisse comprendre les scripts. Il ne se veut en aucun cas un cours/tuto complet et exhaustif.
2 14 Julien Enselme
3 14 Julien Enselme
{{toc}}
4 1 Julien Enselme
5 3 Julien Enselme
h1. Quelques rappels d'Unix
6 3 Julien Enselme
7 3 Julien Enselme
Le langage shell est le langage de script qui vient par défaut avec _tous_ les Unix. En effet, même si désormais d'autres interpréteurs plus modernes sont désormais répandus (bash, csh, zsh, etc.), ils ont tous conservé la compatibilité avec le shell.
8 3 Julien Enselme
9 3 Julien Enselme
Comme pour la plupart des langages de script, il existe deux façons d'exécuter des instructions shell :
10 3 Julien Enselme
11 3 Julien Enselme
* directement dans l'interpréteur
12 3 Julien Enselme
* dans un script shell
13 3 Julien Enselme
14 3 Julien Enselme
Pour lancer un interpréteur shell, rien de plus simple : lancer un terminal (graphique ou tty). Et oui, le shell comprend toutes les commandes Unix que vous avez vues en début d'année (pwd, cd, cp). Vous pouvez donc les réutiliser _telles quelles_ dans vos scripts et utiliser son bon terminal pour faire des boucles, des conditions et j'en passe.
15 3 Julien Enselme
16 1 Julien Enselme
h1. Les bases du shell
17 3 Julien Enselme
18 4 Julien Enselme
Il est très important de comprendre et de garder à l'esprit qu'en shell tout est :
19 4 Julien Enselme
20 4 Julien Enselme
* chaîne de caractères (y compris les nombres) ! Entrez @echo 1 + 1@ dans le terminal pour vous en convaincre.
21 4 Julien Enselme
* commande et que donc elles peuvent prendre des arguments (cela s'éclaircira plus tard)
22 4 Julien Enselme
23 4 Julien Enselme
h2. Syntaxe de base
24 4 Julien Enselme
25 4 Julien Enselme
Les commandes s'écrivent soit :
26 4 Julien Enselme
27 6 Florent Torregrosa
* les unes à la suite des autres séparées par ; (peu recommandé)
28 4 Julien Enselme
* séparées les unes des autres par un saut de ligne
29 4 Julien Enselme
30 4 Julien Enselme
Chaque commande peut prendre des arguments de deux types :
31 4 Julien Enselme
32 4 Julien Enselme
* les arguments courts (l, r, h pour @ls@ par exemple) qui sont passés comme suit : @CMD -ARG@
33 4 Julien Enselme
* les arguments longs (recursive pour @rsync@ par exemple) qui se passent comme ceci : @CMD --ARGUMENT@
34 4 Julien Enselme
35 4 Julien Enselme
Il est évidement possible de passer plusieurs arguments à une même commande.
36 4 Julien Enselme
37 6 Florent Torregrosa
{{tip(Certains arguments existent sous une forme courte et une forme longue. Consulter le manuel de la commande pour plus de détails. Le manuel contient également la liste complète des arguments supportés par une commande.)}}
38 4 Julien Enselme
39 4 Julien Enselme
{{note(Certains commandes ne respectent pas la convention énoncée ce-dessus. Leurs arguments long se passent avec un seul - (find en est un exemple))}}
40 4 Julien Enselme
41 5 Julien Enselme
h2. Valeurs de retour des commandes et exception
42 5 Julien Enselme
43 6 Florent Torregrosa
Une fois qu'une commande s'est exécutée, elle renvoie une valeur de retour afin "d'informer" l'utilisateur. Cette valeur permet en effet de savoir si la commande s'est exécutée correctement. Voici les valeurs de retour possibles et leur signification :
44 5 Julien Enselme
45 5 Julien Enselme
* 0 : tout va bien
46 5 Julien Enselme
* 1 : erreur
47 5 Julien Enselme
* 2 : erreur grave
48 5 Julien Enselme
49 6 Florent Torregrosa
Vous pouvez vous aussi utiliser ces valeurs de retour. Par défaut, un script qui se complète correctement retourne 0. Mais vous pouvez (par exemple si un utilisateur tente d'exécuter un script qui nécessite un argument sans) retourner un autre code d'erreur avec la commande @exit@. Il suffit de lui passer le code qu'elle doit retourner. Votre script s'arrêtera alors avec le code d'erreur spécifié.
50 5 Julien Enselme
51 13 Julien Enselme
h2. Exécuter une commande
52 13 Julien Enselme
53 13 Julien Enselme
S’il est facile dans les cas simples d’exécuter une commande, dès lors qu’en shell tout est chaîne de caractères, si vous voulez affecter la sortie d’une commande à une variable, vous ne pouvez pas simplement faire @var=CMD@ car var va alors valoir la chaîne CMD.
54 13 Julien Enselme
55 13 Julien Enselme
Pour obtenir le résultat souhaité vous devez placer CMS entre backquote `` ou entre $(…). Par exemple : @var=`ls`@ ou @var=$(ls)@.
56 13 Julien Enselme
57 13 Julien Enselme
La syntaxe `` serait plus ancienne et supportée partout. La syntaxe $(…) serait plus récente et présente l’avantage de pouvoir imbriquer les commandes sans ambiguïté.
58 13 Julien Enselme
59 4 Julien Enselme
h2. Conditions et itérations
60 7 Julien Enselme
61 11 Julien Enselme
h3. Conditions if … else …
62 7 Julien Enselme
63 7 Julien Enselme
La structure générale d'une condition est la suivante :
64 7 Julien Enselme
65 7 Julien Enselme
<pre>
66 7 Julien Enselme
<code>
67 7 Julien Enselme
if QQC
68 7 Julien Enselme
then
69 7 Julien Enselme
    CMDS
70 7 Julien Enselme
else
71 7 Julien Enselme
    CMDS
72 7 Julien Enselme
fi
73 7 Julien Enselme
</code>
74 7 Julien Enselme
</pre>
75 7 Julien Enselme
76 7 Julien Enselme
Le @else@ est facultatif. Il est aussi possible de regrouper @if@ et @then@ en une seule ligne comme ceci : @if QQC ; then@.
77 7 Julien Enselme
78 7 Julien Enselme
La question que vous devriez avoir est que mettre à la place de @QQC@. Il y a deux possibilités :
79 7 Julien Enselme
80 7 Julien Enselme
* la fonction @test@
81 7 Julien Enselme
* une commande
82 7 Julien Enselme
83 11 Julien Enselme
h4. La fonction test
84 7 Julien Enselme
85 7 Julien Enselme
{{important(Dans toute la suite, il faudra faire très *attention aux espaces*)}}
86 7 Julien Enselme
87 7 Julien Enselme
La fonction @test@ s'utilise en général comme suit : @if [ ARGS ]@
88 7 Julien Enselme
89 7 Julien Enselme
*IMPORTANT* : La syntaxe *@if [[ ARGS ]]@* n'est valide qu'avec *bash*. Voir [[Petit_precis_de_shell#Différences notables avec bash|Différences notables avec bash]]
90 7 Julien Enselme
91 10 Julien Enselme
Pour faire un test, il suffit ensuite de passer les bons arguments à la commande. Par exemple, pour tester si une chaîne est vide : @if [ -z $chaine ]. Si l’argument a besoin de deux paramètres pour fonctionner, mettre un paramètre de chaque côté de celui-ci. Par exemple, pour faire un test d’égalité de chaîne de caractères : @CHAINE1 = CHAINE2@.
92 10 Julien Enselme
93 10 Julien Enselme
On peut aussi combiner les arguments avec des ET et des OU avec les options @-a@ et @-o@. Le caractère "!" permet de faire une négation.
94 10 Julien Enselme
95 10 Julien Enselme
Voir ci-dessous pour la liste complète.
96 10 Julien Enselme
97 10 Julien Enselme
{{important(En shell, tout est chaîne de caractère. Bien faire attention au type que l’on veut tester (chaîne ou nombre))}}
98 10 Julien Enselme
99 10 Julien Enselme
h5. Tests sur les chaînes de caractères
100 10 Julien Enselme
101 10 Julien Enselme
|_. Argument |_. Signification |
102 10 Julien Enselme
| = | égalité |
103 10 Julien Enselme
| -z | chaîne vide |
104 10 Julien Enselme
| -n | chaîne non vide |
105 10 Julien Enselme
106 10 Julien Enselme
h5. Tests sur les nombres
107 10 Julien Enselme
108 10 Julien Enselme
|_. Argument |_. Signification |
109 10 Julien Enselme
| -eq | égalité |
110 10 Julien Enselme
| -ne | non égalité |
111 10 Julien Enselme
| -lt | strictement plus petit |
112 10 Julien Enselme
| -gt | strictement plus grand |
113 10 Julien Enselme
| -ge | plus grand ou égal |
114 10 Julien Enselme
| -le | plus petit ou égal |
115 10 Julien Enselme
116 7 Julien Enselme
h4. Test avec une commande
117 1 Julien Enselme
118 10 Julien Enselme
Comme indiqué précédemment, une commande qui s’exécute correctement est considérée comme vrai. Ainsi, il est tout a fait possible, par exemple, pour savoir si on arrive à se connecter à un serveur mysql de faire simplement : @if mysql -h HOST -u asso -pTATA@.
119 10 Julien Enselme
120 10 Julien Enselme
{{tip(Parfois vous pourrez rencontrer des problèmes. Pensez alors à donner cette commande en argument à la fonction test)}}
121 7 Julien Enselme
122 12 Julien Enselme
h3. Boucles while/until
123 12 Julien Enselme
124 12 Julien Enselme
La structure générale est la suivante :
125 12 Julien Enselme
<pre>
126 12 Julien Enselme
while QQC
127 12 Julien Enselme
do
128 12 Julien Enselme
    CMD
129 12 Julien Enselme
done
130 12 Julien Enselme
</pre>
131 12 Julien Enselme
132 12 Julien Enselme
Il est possible de regrouper @while QQC@ et le @do@ en @while QQC ; do@. Le QQC peut être remplacer par exactement les mêmes choses que pour la condition. Se référer à cette section pour les précisions.
133 12 Julien Enselme
134 12 Julien Enselme
Le shell propose également le mot clé @until QQC@ qui fait une action jusqu’à ce que QQC soit réalisé.
135 12 Julien Enselme
136 12 Julien Enselme
h3. Boucle for
137 12 Julien Enselme
138 12 Julien Enselme
L’utilisation de la boucle for en shell ressemble à celle de python. La structure générale est la suivante :
139 12 Julien Enselme
<pre>
140 12 Julien Enselme
for var in `CMD`
141 12 Julien Enselme
do
142 12 Julien Enselme
   CMD
143 12 Julien Enselme
done
144 12 Julien Enselme
</pre>
145 12 Julien Enselme
146 12 Julien Enselme
La variable _var_ va alors prendre une à une les valeurs données par CMD. Par exemple, @for file in `ls`@ la variable var va prendre tour à tour le nom de tous les fichiers et dossiers donnés par la commande @ls@.
147 12 Julien Enselme
148 12 Julien Enselme
Vous pouvez également utiliser for pour boucler d’un nombre à un autre avec la syntaxe : @for i in {2..9}@
149 12 Julien Enselme
150 16 Julien Enselme
{{warning(2..9 semble être du bash. à revoir)}}
151 16 Julien Enselme
152 18 Julien Enselme
h1. Paramètres de scripts
153 18 Julien Enselme
154 18 Julien Enselme
h2. Généralités
155 18 Julien Enselme
156 18 Julien Enselme
Un script peut prendre des paramètres qui ont le même but que les arguments d'une fonction : lui passer des informations. Un paramètre peut être :
157 18 Julien Enselme
158 18 Julien Enselme
* une variable
159 18 Julien Enselme
* une chaîne de caractère (donc un nombre, en shell on ne fait pas la distinction). Si la chaîne à passer en paramètre contient plusieurs mots séparés par des espaces, ne pas oublier de la mettre entre ' ou ".
160 18 Julien Enselme
161 18 Julien Enselme
{{tip(Si une varaible coucou contient la chaîne 'salut', alors '$coucou toi' sera compris _$coucou toi_ tandis que "$coucou toi" sera interprété en _salut toi_)}}
162 18 Julien Enselme
163 18 Julien Enselme
Les paramètres se passent à un script comme ceux d'une commande. Ils sont ensuite disponibles dans l'ordre avec des numéros :
164 18 Julien Enselme
165 18 Julien Enselme
* le premier : $1
166 18 Julien Enselme
* le deuxième : $2
167 18 Julien Enselme
* et ainsi de suite
168 18 Julien Enselme
169 18 Julien Enselme
{{important(Le shell ne supporte *que* 9 paramètres)}}
170 18 Julien Enselme
171 18 Julien Enselme
h2. Les paramètres spéciaux
172 18 Julien Enselme
173 18 Julien Enselme
* $0 : contient le nom du script
174 18 Julien Enselme
* $# : contient le nombre d'arguments passés au script
175 18 Julien Enselme
{{important(Le paramète $0 est toujours passé au script. $# est donc toujours supérieur ou égale à 1)}}
176 18 Julien Enselme
* $* : l'ensemble des paramètres en un seul argument A DETAILLER
177 18 Julien Enselme
* $? : le code de retour de la dernière commande invoquée
178 18 Julien Enselme
* $$ : le PID du shell qui exécute le script
179 18 Julien Enselme
* $! : le PID du dernier processus lancé en arrière plan
180 18 Julien Enselme
* $@ : L'ensemble des arguments, un argument par paramètre A DETAILLER
181 18 Julien Enselme
182 18 Julien Enselme
h2. Les commandes shift et set
183 18 Julien Enselme
184 18 Julien Enselme
La commande @set@ permet d'affecter les paramètres. Ainsi @set bonjour salut bonsoir@ va initialiser $1 à bonjour, $2 à salut et $3 à bonsoir. Les paramètres spéciaux $#, $* et $@ sont mis à jour.
185 18 Julien Enselme
186 18 Julien Enselme
La commande @shift@ permet de décaler les variables. Ainsi, si après @shift@ $1 prend la valeur de $2 et ainsi de suite. @shift n@ décale les arguments de n
187 18 Julien Enselme
188 17 Julien Enselme
h1. Les fonctions
189 17 Julien Enselme
190 17 Julien Enselme
Il est tout à fait possible de définir en shell des fonctions que ce soit dans un script ou un terminal. La syntaxe est la même.
191 17 Julien Enselme
192 17 Julien Enselme
<pre>
193 17 Julien Enselme
nom_de_la-foncion () {
194 17 Julien Enselme
  CMDS
195 17 Julien Enselme
}
196 17 Julien Enselme
</pre>
197 17 Julien Enselme
198 17 Julien Enselme
Les fonctions ainsi créées s'utilise comme les commandes classiques et leurs arguments se manipulent exactement comme ceux d'un script. Voir [[Petit_precis_de_shell#Les-redirections-de-flux|la section dédiée]]. Il faut néanmoins faire attention à deux points :
199 17 Julien Enselme
200 17 Julien Enselme
* la portée des varibles
201 17 Julien Enselme
* la valeur de retour
202 17 Julien Enselme
203 17 Julien Enselme
Par défaut, les varialbes définies dans la fonction resteront accessibles une fois la fonction exécutée. De même les varables définies auparavant restent acessibles dans la fonction. *Ces varaibles sont donc globales par défaut.* Pour qu'une variables soit locale, il faut utiliser le mot clé @local@ lors de sa définition. Par exemple : @local nom=clubdrupal@.
204 17 Julien Enselme
205 17 Julien Enselme
Pour qu'une fonction en bash retourne une valeur comme vous pouvez en avoir l'habitude dans d'autre langage, il faut utiliser la commande @echo@. En effet, il n'existe pas d'instruction @return@ puisque par défaut les variables sont globales. Il faut alors faire très attention. Par exemple avec la fonction suivante :
206 17 Julien Enselme
207 17 Julien Enselme
<pre>
208 17 Julien Enselme
<code class="bash">
209 17 Julien Enselme
x_files () {
210 17 Julien Enselme
  top_secret=`dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -f1 -d" "`
211 17 Julien Enselme
  echo $top_secret
212 8 Julien Enselme
}
213 8 Julien Enselme
</code>
214 8 Julien Enselme
</pre>
215 9 Julien Enselme
216 9 Julien Enselme
* Si on fait @x_files@ on affiche à l'écran le contenu de @$top_secret@
217 9 Julien Enselme
* Si on fait @passwd=`x_files`@ on affecte à la variable @$passwd@ le contenu de @$top_secret@
218 9 Julien Enselme
219 9 Julien Enselme
h1. Les redirections de flux
220 1 Julien Enselme
221 19 Julien Enselme
Les flux représentent les sorties générées par les commandes. Par défaut, il existe deux flux :
222 19 Julien Enselme
223 19 Julien Enselme
* Le flux standard
224 19 Julien Enselme
* Le flux d'erreur
225 19 Julien Enselme
226 19 Julien Enselme
Par défaut, il s'affiche sur la sortie standard (votre écran pour être bref). Il peut s'avérer intéressant d'envoyer ces flux ailleurs (logs, le néant, etc.). Pour cela, on va les rediriger. Par exemple pour rediriger la sortie de @ls@ dans un fichier nommé toto, on fait :
227 19 Julien Enselme
228 19 Julien Enselme
* @ls > toto@
229 19 Julien Enselme
* *ou*
230 19 Julien Enselme
* @ls >> toto@
231 19 Julien Enselme
232 19 Julien Enselme
La première solution efface le contenu du fichier puis écrit dedans. La seconde ajoute la sortie à la fin du fichier. On a ici redirigé le flux standard. Pour rediriger les flux d'erreurs, on utilise les symboles @2>@ ou @2>>@. On peut évidemment combiner les deux : @ls -R / > mes_fichiers.txt 2> errors.log@ avec toutes les variantes possibles.
233 19 Julien Enselme
234 19 Julien Enselme
Pour rediriger l'erreur au même endroit que l'entrée, on peut faire @ls > toto 2> toto@ ou plus simplement @ls > toto 2>&1@.
235 19 Julien Enselme
236 19 Julien Enselme
Pour rediriger une sortie vers le néant, on l'envoie dans /dev/null.
237 9 Julien Enselme
238 8 Julien Enselme
h1. Importer une configuration
239 8 Julien Enselme
240 8 Julien Enselme
@. config-file.sh@
241 8 Julien Enselme
242 8 Julien Enselme
h1. Mode debug
243 1 Julien Enselme
244 1 Julien Enselme
Lorsqu’un de vos scripts shell bug il peut être difficile de savoir d’où vient le problème. Heureusement, le shell propose un mode débug qui vous dit pour chaque ligne comment elle est exécuté, avec quels paramètres (les variables sont remplacées par leur contenu).
245 1 Julien Enselme
246 1 Julien Enselme
Il suffit de faire : @sh -x SCRIPT@
247 1 Julien Enselme
248 8 Julien Enselme
h1. Différences notables avec bash
249 15 Julien Enselme
250 18 Julien Enselme
* RANDOM
251 18 Julien Enselme
* let
252 18 Julien Enselme
* &> et |&
253 18 Julien Enselme
* le nombre de paramètres
254 18 Julien Enselme
255 1 Julien Enselme
h1. Divers
256 1 Julien Enselme
257 7 Julien Enselme
h2. Différences entre la sortie de ls et de find
258 9 Julien Enselme
259 9 Julien Enselme
ls : chemin relatif ; find auei : chemin absolu
260 18 Julien Enselme
261 18 Julien Enselme
h1. Sources et liens externes
262 18 Julien Enselme
263 18 Julien Enselme
* http://www.commentcamarche.net/faq/5444-bash-les-parametres