IFT2240, démo # 2:
Commandes shell et Scripts en Bash
Le SHELL est le programme qui lit et interprete les commandes entrees au terminal. Plusieurs shells ont ete developpes a partir de la premiere version: sh, le Borne shell. Ils se ressemblent beaucoup et different surtout dans la syntaxe des variables et celle des énoncés de controle (IF, WHILE) employes dans les SCRIPTs.
Commandes, arguments et options
Une ligne de commande Shell est un ensemble de mots
séparés par des blancs ou des TABS. Le premier mot est la
commande. On trouve par la suite des options
précédes par des tirets, "-". Et enfin on trouve
un (ou des) argument(s) qui sont souvent des noms de fichiers.
Exemple: lp -d lp1 -h myfile
lp : commande (imprimer fichier) ,
-d : option (envoyer le resultat l'imprimante lp1 )
lp1 : parametre de l'option -d
-h : option ( ne pas imprimer de bannière ) ,
myfile : argument , c'est le nom du fichier à imprimer
Caractères spéciaux
Plusieurs caractères ont un sens spécial dans les commandes shells
Caractère
|
Signification
|
~
|
Repertoire Home
|
#
|
Commentaire
|
$
|
Début d'une variable
|
| |
Pipe |
&
|
tâche en arrière plan
|
<
|
Redirection d'Input
|
>
|
Redirection d'output
|
;
|
Separateur de commandes
|
{ ... }
|
Bloc de commandes
|
|
|
Caractère
|
Signification
|
'...'
|
Strong quote
|
"..."
|
weak quote
|
\
|
quote le caractère qui suit
|
`
|
Evaluer commande qui suit
|
|
Patrons Wildcard
|
* |
matche chaîne
quelconque
|
? |
matche 1 Caractère
|
[....]
|
matche UN car. de l'ensemble |
|
Caractères Wildcard
Un patron wildcard dans une commande est remplace par tous les noms de fichiers
du repertoire courant qui matche le patron. Soit présent dans ce repertoire les
5 fichiers suivants:
a.log, a1.c, a4.c, aa.c et b1.c
commande | équivaut à |
ls a?.c | ls a1.c a4.c aa.c |
ls a* | ls a.log a1.c a4.c aa.c |
ls a[a4]* | ls a4.c aa.c |
ls *[0-9].c | ls a1.c a4.c b1.c |
Quotes: ", ', \
Pour imprimer des caractères spéciaux, il faut les "quoter", autrement on
peut avoir des surprises. Par exemple, l'énoncé suivant n'imprime rien:
- % echo 3 * 4 > 5 ?
car ">" redirige l'output vers un fichier nommé "5"; "*" est remplace par la
liste de tous les fichiers (y compris "5") et "?" remplace par la liste des
fichiers dont les noms on une lettre. Pour imprimer "3 * 4 > 5 ", il faut mettre
les arguments entre guillemets (") ou apostrophes (') ou mettre un "\" devant chaque
caractère dangereux:
% echo "3 * 4" ' > ' 5 \?
Le dollar "$" et le backquote "`" gardent leur fonctions
(variable et evaluation) l'intérieur des "..." mais sont considérés
comme des caractères ordinaires dans un '...'. Ceci donne:
% var=1234
% echo "$var vaut 1234" # imprime "1234 vaut 1234"
% echo '$var vaut 1234' # imprime "$var vaut 1234"
Arithmetique
Bien qu'on puisse faire autrement, p.e. avec backquote "`" ou expr,
nous recommandons la syntaxe $(( ... expr... )) qui est plus robuste que les autres.
Les opérateurs habituels s'appliquent:
+, -, *, %, /
.
% x=5 ; y=$(( $x - 2))
% echo $(( $x * (3+$y)-1))
Scripts (en bash)
References
Un script est une suite de commandes dans un fichier qu'on peut faire exécuter
en tappant le nom du fichier comme commande.
Voici l'exemple de script1 qui compile tous les programmes java du
répertoire courant et les regroupe dans JAR qui est ensuite déplacé ailleurs.
Notez que pour être exécuté, fichier script doit être exécutable;
ce qui est fait avec "chmod a+x script1".
% cat script1
#!/bin/bash
echo Creation de MonApp.jar
javac *a
jar -cf MonApp.jar *class
cp MonApp.jar $HOME/ift2240 |
% chmod a+x script1
% ./script1
La première ligne du script indique le shell utilisé pour interprter
le contenu du fichier. Les autres lignes du fichier contiennent des commandes.
- #! suivi du path vers le shell (ex: #!/bin/tcsh) Indique que le shell tcsh interprètera le fichier.
- # avec rien sur la ligne. Indique que le c-shell interprètera le fichier.
- Sinon, le Bourne shell interpretera le fichier.
Dans ce qui suit, nous utiliserons BASH comme exemple de shell.
Les variables
- L'affectation de valeur crée la variable au besoin
% nom=valeur # "%" denote le PROMPT de Unix
% echo $nom
- Pas d'espace autour du "=" !
- Accès à la valeur avec $nom
- Une variable inconnue est remplacée par la chaine vide
- Impression de la table des variables avec: set
- Pour forcer la substitution d'une variable dans une chaine: ${nom}
% val=fred
% echo A${var}1 A$var1 # $var1, inconnu, disparait !
Variables exportées
L'exportation d'une variable veut dire qu'elle sera copiée dans
tout nouveau shell (ou process) créé à partir du shell courant.
export nom
export # imprime la liste des variables
exportées
Variables d'environnement
Ce sont les variables systèmes prédéfinies dont la liste est consultable avec: env
Les plus utiles sont: $HOME, $PATH, $USER, $PS1, $SHELL, $ENV, $PWD
Variables spéciales ( utilisable dans un script )
- $1...$9, $n : se réfère au n'ieme paramètre
de la ligne de commande.
- $0 : se réfère au nom du script.
- $* : liste des paramètres de la ligne de commande.
- $# : le nombre de paramètres
- $? : (ou $status) valeur de sortie de la dernière commande.
- $$ : identification du processus du shell.
Nous utiliserons souvent "echo $?" pour montrer le résultats de comparaisons (tests)
Entrées-sorties
- echo : commande d'impression normale
- echo -n : ne saute pas de ligne apres impression
- echo -e : permet les caracteres spéciaux:
- \n (saut ligne)
- \t (tabulation)
- \c (fin sans saut de ligne)
- read : lecture à partir du clavier
Exemple:
% echo -n "Nom: " ; read nom ; echo -e "\tVous etes $nom"
Nom: Jean
Conditionels: if/then/else
if condition
then énoncés...
elif condition
then énoncés...
else énoncés...
fi
|
Notes:
- Les parties elif et else peuvent être absentes
- Il doit y avoir un délimiteur - fin-de-ligne ou ";" - devant les
mots-clés:
then, elif, else et fi
- On utilise le plus souvent les fin-de-lignes dans les scripts et le ";" pour les commandes au terminal.
Voici un exemple au terminal [ Note: la syntaxe des conditions est traitée dans
la section suivante ] :
% x=3
% if [ $x = 0 ]; then echo "Zero"; else echo "Pas zero." ; fi
Pas zero.
% if [ $x = 3 ]; then echo "TRUE"; else echo "FALSE" ; fi
TRUE
|
Exemples de scripts:
#!/bin/bash
if grep "^toto" /etc/passwd > /dev/null
then
echo "Toto a déjà un compte"
fi
#!/bin/bash
if diff $1 $2 > /dev/null ; then
then
echo "Les fichiers sont identiques"
else
echo "Les fichiers sont differents"
fi
#!/bin/bash
if [ $# = 0 ]
then
echo "Erreur, la commande exige au moins un argument .."
exit 1
elif [ $# = 1 ] ; then
echo "Donner le second argument : "
read arg2
fi
|
Condition / Test
La condition d'un IF peut dependre du succes d'une commande (comme avec GREP dans le
script ci-dessus); mais le plus souvent c'est un TEST sur le contenu d'une variable ou
l'attribut d'un fichier. Le test
admet 2 syntaxes ( la seconde est la plus utilisée) :
- test opérateur fichier
- [ opérateur fichier ]
Attention! Il faut laisser des BLANCS autour des opérateurs [ et des crochets ] !
Opérateurs de nombres |
Signification |
-eq |
= |
-ne |
différents |
-lt , -le |
< , <= |
-gt , -ge |
> , >= |
Opérateurs de chaines |
|
= , != |
égal , différent |
-z , -n |
vide , non_vide |
Opérateurs booléens |
true = 0 et
false = 1 ou autre chose |
exp1 -a exp2 |
and: 0 si les 2 expr sont vraies |
exp1 -o exp2 |
or: 0 si une expr = 0 |
! exp |
not |
Pour les fichiers, voici une liste partielle des operateurs (unaires) disponibles:
- -r Le fichier peut être lu.
- -w Le fichier peut être écrit.
- -x Le fichier peut être exécuté.
- -e Le fichier existe.
- -f Le fichier est un fichier régulier.
- -d Le fichier est un répertoire.
- -l Le fichier est un lien.
Exemple:
% f="/root" ; [ -d "$f" -a -x "$f" ] ; echo $?
% note=48; [ $note -lt 45 -o $note -ge 50 ] && echo "Revision de note?"
|
Note: Le "&&" ci-dessus est un ET optimisant qui n'évalue sa partie droite
que si la partie gauche est TRUE. Cette une astuce souvent utilisée dans des scripts
pour réaliser un IF...THEN de façon compacte.
Ci dessous on voit ce qui se passe si on oublie les blancs autour des crochets.
% x=1; [ $x = 1 ] && echo TRUE
TRUE
% x=1; [$x = 1] && echo TRUE
bash: [1: command not found
|
Boucles
1) for var in list...
do
énoncés
....
done
2) while [ test ]
do
énoncés ...
done
|
- Les fin de lignes ( ou ";" ) avant do et done sont essentielles.
- La liste de la version for est souvent générées en utilisant un patron wildcard
accéder à la liste des fichiers dans le repertoire où le script exécute.
Exemples:
#!/bin/bash
for file in *
do
echo "Adding .html extension to $file..."
mv $file $file.html
sleep 1
done
#!/bin/bash
echo -n "Nom: " ; read nom
while [ -z "$nom" ] ; do
echo -n " Nom: " ; read nom
done
|
Choix multiple: Case
case variable in
patron1 ) énoncés ...
;;
patron2 | patron3 ...) énoncés ...
;;
... etc ...
* ) énoncés ... ;;
esac
|
Ici la sélection d'une alternative se fait en comparant la
valeur d'une variable les patrons des divers alternatives.
Ces patrons sont les mêmes que pour le filtrage de fichiers.
Pour le même cas, on peut mettre plusieurs patrons séparés par "|".
Exemples:
case $param in
0|1|2|3|4|5|6|7|8|9 )
echo $param est un chiffre ;;
[0-9]*) echo $param est un nombre ;;
[a-zA-Z]*) echo $param est un nom ;;
*) echo $param de type non prevu ;;
esac
while true; do
echo -n "list the current dir? (y/n) "
read yn
case $yn in
y* | Y*) ls -l . ; break ;;
[nN]* ) echo "skipping" ; break ;;
q* ) exit ;;
* ) echo "unknown response. Asking again" ;;
esac
done |
Fonctions
function_name ()
{
énoncés
...
return
}
|
En Bash, on peut définir des fonctions qui fonctionnent comme des scripts
locaux. On les apellent comme des scripts sans parenthèses pour les paramètres.
Et dans le corps des fonctions, on accède à ces paramètres avec $1, $2, ...
La définition de la fonction doit être placée avant la première utilisation.
#!/bin/bash
mafonction ()
{
echo " - Appel de $0 avec: $* "
return
}
echo "Debut du test"
mafonction 1 2 3
mafonction Pierre et Marie
|
Résultat:
$ ./s1
Debut du test
- Appel de ./s1 avec: 1 2 3
- Appel de ./s1 avec: Pierre et Marie
|
Date de dernière modification: 2004-09-9
Modifier le: 2004-01-15
Auteur: Jean Vaucher