Programmation SHELL
Programmation SHELL
PROGRAMMATION SHELL
I - INTRODUCTION:
Le Shell est un interpréteur de commandes. Plus qu'une simple couche isolante entre le noyau du
système d'exploitation et l'utilisateur, il est aussi un véritable langage de programmation très
puissant avec notamment une gestion des variables, des tests et des boucles, des opérations sur des
variables, des fonctions…. Un programme Shell, appelé un script, est un outil facile à utiliser pour
construire des applications en « regroupant » des appels système, outils, utilitaires et binaires
compilés. Virtuellement, le répertoire entier des commandes UNIX, des utilitaires et des outils est
disponible à partir d'un script Shell. Si ce n'était pas suffisant, les commandes Shell internes, telles
que les constructions de tests et de boucles, donnent une puissance et une flexibilité
supplémentaires aux scripts. Les scripts Shell conviennent particulièrement bien pour les tâches
d'administration du système et pour d'autres routines répétitives ne réclamant pas les particularités
d'un langage de programmation structuré complet.
1 – LES DIFFERENTS SHELLS
De par sa qualité de "programme externe", il n'est pas unique. En effet, rien n'empêche n'importe
quel programmeur de programmer une boucle qui attend une chaîne au clavier, analyse cette chaîne
et appelle ensuite le système pour exécuter l'ordre demandé. C'est la raison pour laquelle il existe
plusieurs shells
Il existe de nombreux shells qui se classent en deux grandes familles
La famille Bourne shell :.
le Bourne Shell ("/bin/sh")
le Korn Shell ("/bin/ksh")
le Job Shell ("/bin/jsh")
le Shell réseau ("/bin/rsh")
le Bourne Again Shell ("/bin/bash") qui a repris le Bourne Shell mais qui l'a agrémenté de
nouvelles fonctionnalités (rappel de commandes, complétion automatique, etc.)
l'Almquist Shell ("/bin/ash") améliorant le Bourne Shell tout en étant plus compact que le
Bourne Again Shell
Le Bourne Shell (sh) est le premier Shell crée par STEPHEN BOURNE et reste celui dont tout
système Unix a besoin pour lancer les outils de configuration au démarrage de la machine. Les
Shell ksh ("Korn Shell") et bash ("Bourne Again Shell") utilisent des syntaxes plus riches
mais restent compatibles avec sh. Le Shell par défaut est bash (Bourne Again SHell) et a été conçu
en 1988 par BRIAN FOX dans le cadre du projet GNU
La famille C shell : csh, tcsh
le C Shell ("/bin/csh")
le Toronto C Shell ("/bin/tcsh")
Le csh ("C_Shell"), et le tcsh ("Toronto C-Shell") ont par contre des syntaxes beaucoup plus
différentes de sh et très proches de celle du langage C.
Il existe un autre Shell appelé zsh (Zéro Shell) et contient les caractéristiques des deux familles
précédentes avec des syntaxes riches et compatible aussi avec le sh.
Un shell possède un double aspect :
- un aspect environnement de travail
- un aspect langage de programmation.
Il permet donc :
l'utilisation de variables
52
GANDHI
Programmation Shell
la mise en séquence de commandes
l'exécution conditionnelle de commandes
la répétition de commandes
2. Types de Commandes
Le Shell distingue deux sortes de commandes :
les commandes internes
les commandes externes.
2.1. Commandes internes
Une commande interne est une commande dont le code est implanté au sein de l’interpréteur de
commande. Cela signifie que, lorsqu’on change de Shell courant ou de connexion, par exemple en
passant de bash au C-shell, on ne dispose plus des mêmes commandes internes.
Exemples: cd , echo , for , pwd
Sauf dans quelques cas particuliers, l’interpréteur ne crée pas de processus pour exécuter une
commande interne.
2.2. Commandes externes
Une commande externe est une commande dont le code se trouve dans un fichier ordinaire. Le Shell
crée un processus pour exécuter une commande externe. Parmi l’ensemble des commandes externes
que l’on peut trouver dans un système, nous utiliserons principalement les commandes unix
Exemple : ls, mkdir, vi, sleep et les fichiers shell.
Remarque : pour connaitre le statut d’une commande, on utilise la commande interne type.
Exemple :
$ type mkdir
mkdir is /bin/mkdir => mkdir est une commande externe
$ type echo
echo is a shell builtin => echo est une commande interne
$
logique).
52
GANDHI
Programmation Shell
On utilise le caractère & pour lancer une commande en arrière-plan.
Exemple:
$ sleep 5 &
[1] 3859
$ ps
PID TTY TIME CMD
3778 pts/1 00:00:00 bash
3859 pts/1 00:00:00 sleep
3860 pts/1 00:00:00 ps
$ => l’utilisateur a appuyé sur la touche entrée mais sleep n’était pas terminée
$ => l’utilisateur a appuyé sur la touche entrée et sleep était terminée
[1]+ Done sleep 5
$
Dans cet exemple, la commande sleep 5 (suspendre l’exécution pendant 5 secondes) est lancée en
arrière-plan. Le système a affecté le numéro d’identification 3859 au processus correspondant
tandis que le Shell a affecté un numéro de travail (ou numéro de job) égal à 1 et affiche [1].
L’utilisateur peut, en parallèle, exécuter d’autres commandes (dans cet exemple, il s’agit de la
commande ps). Lorsque la commande en arrière-plan se termine, le Shell le signale à l'utilisateur
après que ce dernier ait appuyé sur la touche entrée.
Pour une application complexe où une programmation structurée est nécessaire (typage des
variables, prototypage de fonctions, tableaux multi - dimensionnels, listes chaînées, arbres, etc.)
Pour des situations où la sécurité est importante (protection contre l'intrusion, le vandalisme)
Pour des applications qui accèdent directement au matériel
Pour des applications qui devront générer ou utiliser une interface graphique utilisateur (G.U.I.)
Pour des applications propriétaires (un script est forcément lisible par celui qui l'utilise)
Pour toutes ces situations, Unix offre une gamme de langages de scripts plus puissants comme le
Perl, Tcl, Python, Ruby ; voire des langages compilés de haut niveau comme le C et le C++.
6. Moyens de Programmation
Il existe deux moyens de "programmer" en Shell.
Le premier, est dit en "direct". L'utilisateur tape "directement" la ou les commandes qu'il veut
lancer. Si cette commande a une syntaxe qui l'oblige à être découpée en plusieurs lignes, le Shell
indiquera par l'affichage d'un "prompt secondaire" que la commande attend une suite et n'exécutera
réellement la commande qu'à la fin de la dernière ligne.
Exemple:
52
GANDHI
Programmation Shell
$ date
Tue Mar 27 17:26:50 NFT 2014
$pwd
/home/doum
$ if test 5 = 5
> then
> echo vrai
> fi
vrai
$
Le second, est dit en "script" ; appelé aussi "batch" ou "source Shell". L'utilisateur crée un fichier
texte par l'éditeur de son choix (ex : "vi"). Il met dans ce script toutes les commandes qu'il voudra
lui faire exécuter ; en respectant la règle de base de ne mettre qu'une seule commande par ligne.
Une fois ce script fini et sauvegardé, il le rend exécutable par l'adjonction du droit "x". Il peut
ensuite lancer l'exécution de ce fichier comme n'importe quelle autre commande Unix (attention
cependant au contenu de la variable "PATH" qui indique où aller chercher une commande lorsqu'on
la lance sans préciser où elle se trouve).
Toutes les commandes inscrites dans le fichier texte seront exécutées séquentiellement
Exemple :
Lancement de l'éditeur
$ vim script1
Remarque :
L'adjonction du droit "x" n'est pas obligatoire, mais l'utilisateur devra alors demander
spécifiquement à un Shell quelconque d'interpréter le "script".
52
GANDHI
Programmation Shell
c’est un langage interprété : les erreurs peuvent être facilement localisées et traitées ;
d’autre part, des modifications de fonctionnalités sont facilement apportées à l’application
sans qu’il soit nécessaire de recompiler et faire l’édition de liens de l’ensemble
le Shell manipule essentiellement des chaines de caractères: on ne peut donc construire des
structures de données complexes a l’aide de pointeurs, ces derniers n’existant pas en Shell.
Ceci a pour avantage d’éviter des erreurs de typage et de pointeurs mal gérés. Le développeur
raisonne de manière uniforme en termes de chaines de caractères.
le langage est adapté au prototypage rapide d’applications : les tubes, les substitutions de
commandes et de variables favorisent la construction d’une application par assemblage de
c’est un langage ≪ glu ≫ : il permet de connecter des composants écrits dans des langages
commandes préexistantes dans l’environnement Unix.
développeurs, les Shell utilisent une syntaxe ≪ ésotérique ≫ d’accès difficile pour le
issus d’Unix, système d’exploitation écrit à l’ origine par des développeurs pour des
débutant
l’oubli ou l’ajout d’un caractère espace provoque facilement une erreur de syntaxe
certains caractères spéciaux, comme les parenthèses, ont des significations différentes
suivant le contexte ; en effet, les parenthèses peuvent introduire une liste de commandes,
une définition de fonction ou bien imposer un ordre d’évaluation d’une expression
arithmétique.
8. Impératifs
Comme il l'a été dit, le Shell est un "interpréteur". C'est à dire que chaque ligne est analysée, vérifiée et
exécutée. Afin de ne pas trop limiter la rapidité d'exécution, il y a très peu de règles d'analyse. Cela implique
une grande rigidité d'écriture de la part du programmeur. Une majuscule n'est pas une minuscule ; et
surtout, deux éléments distincts sont toujours séparés par un espace… à une exception près qui sera vue
plus tard.
Enfin, le premier mot de chaque ligne, si la ligne n'est pas mise en commentaire, doit être une instruction
Shell "correcte". On appelle "instruction" soit
$ echoBonjour
sh: echoBonjour: not found
$ echo Bonjour
Bonjour
52
GANDHI
Programmation Shell
Toutes les instructions et commandes sont regroupées au sein d’un script. Lors de son exécution,
chaque ligne sera lue une à une et exécutée. Une ligne peut se composer de commandes internes ou
externes, de commentaires ou être vide. Plusieurs instructions par lignes sont possibles, séparées par
le « ; » ou liées conditionnellement par « && » ou « || ». Le « ; » est l’équivalent d’un saut de ligne.
Par convention les Shell scripts se terminent généralement (pas obligatoirement) par « .sh » pour le
Bourne Shell et le Bourne Again Shell, par « .ksh » pour le Korn Shell et par « .csh » pour le C -
Shell.
Exemple :
Script1.sh
Scrip1t.ksh
Pour rendre un script exécutable directement on change d’abord le droit d’exécution comme nous
avons vu précédemment par défaut (644) pour donner au moins à l’utilisateur ce droit comme suit :
$ chmod u+x script1.sh
Pour l’exécuter :
$ ./monscript
Pour éviter le ./ :
$ PATH=$PATH:.
$ script1
Quand un script est lancé, un nouveau shell « fils » est créé qui va exécuter chacune des
commandes. Si c’est une commande interne, elle est directement exécutée par le nouveau shell. Si
c’est une commande externe, dans le cas d’un binaire un nouveau fils sera créé pour l’exécuter,
dans le cas d’un shell script un nouveau shell fils est lancé pour lire ce nouveau shell ligne à ligne.
Une ligne de commentaire commence toujours par le caractère « # ». Un commentaire peut être
placé en fin d’une ligne comportant déjà des commandes.
# La ligne suivante effectue un ls
ls # La ligne en question
La première ligne a une importance particulière car elle permet de préciser quel shell va exécuter le
script
#!/bin/sh ou #!/bin/bash
#!/bin/ksh
#!/bin/csh
II. ELEMENTS DE BASE DU LANGAGE
a) L'affichage
L'affichage est la première commande qu'un programmeur débutant pourra être tenté de faire. Cela
lui permet en effet de visualiser directement à l'écran le résultat de ses actions.
L'affichage en Shell se fait avec la commande "echo".
Exemple :
$ echo bonjour tout le monde !
b) Les commentaires
Un commentaire sert à améliorer la lisibilité du script. Il est placé en le faisant précéder du caractère
dièse ("#"). Tout ce qui suit ce dièse est ignoré jusqu'à la fin de la ligne ; ce qui permet de mettre un
commentaire sur une ligne d'instructions. Il ne faut pas oublier alors l'espace séparant la fin
de l'instruction et le début du commentaire. Les lignes commençant avec un # (à l'exception de #!)
sont des commentaires et ne seront pas exécutées.
Exemple1 : # Cette ligne est un commentaire.
echo "Un commentaire va suivre." # Un commentaire ici.
52
GANDHI
Programmation Shell
# Notez l'espace blanc devant
echo "Le # ici ne commence pas un commentaire."
echo 'Le # ici ne commence pas un commentaire.'
echo Le \# ici ne commence pas un commentaire.
echo Le # ici commence un commentaire.
echo ${PATH#*:} # Substitution de paramètres, pas un commentaire.
echo $(( 2#101011 )) # Conversion de base, pas un commentaire.
Exemple2 :
#!/bin/sh
# Ce programme affiche la date
date # Cette ligne est la ligne qui affiche la date
c) Le débogueur
Une procédure longue et difficile peut ne pas réussir du premier coup. Afin de détecter l'erreur, le
Shell offre un outil de débogage. Il s'agit de l'instruction "set" agrémentée d'une ou
plusieurs options suivantes :
v : affichage de chaque instruction avant analyse => il affiche le nom des variables
x : affichage de chaque instruction après analyse => il affiche le contenu des variables
e : sortie immédiate sur erreur
Chaque instruction "set -…" active l'outil demandé qui sera désactivé par l'instruction "set +…". On
peut ainsi activer le "traqueur" sur une portion précise du programme source.
Exemple :
#!/bin/sh
set –x # Activation du débogage à partir de maintenant
date # Cette ligne est la ligne qui affiche la date
set +x # Désactivation du débogage à partir de maintenant
Remarque : Compte tenu du flot important d'informations produit par ces outils, il peut
être avantageux de lui préférer un affichage des variables pouvant causer l'erreur (commande
"echo").
Autre exemple : (ne fonctionne qu'une seule fois) :
#!/bin/rm # Ce script sera traité par le programme "/bin/rm" (effacement)
# Le script s'efface donc lui-même - Ici le script est déjà effacé
# Quoi que l'on mette ici, cela ne sera pas exécuté, cela n'existe déjà
plus…
52
GANDHI
Programmation Shell
Exercice d’application
1) A l’aide d’un éditeur de texte de votre choix, créer un fichier exercice1 contenant les lignes
suivantes :
#!/bin/bash
# ici commence un commentaire
echo -n "La date du jour est: "
date
La notation #! en première ligne d'un fichier interprète précise au Shell courant quel interpréteur
doit être utilise pour exécuter le script Shell (dans cet exemple, il s’agit de /bin/bash).
La deuxième ligne est un commentaire.
Pour lancer l’exécution du fichier Shell, on peut utiliser aussi la commande :
bash nom_fichier.nomshell
Exemple:
$ bash exercice1.bash
2) Ecrire un programme shell exercice2 qui affiche le nom de connexion de l'utilisateur et le chemin
absolu de son répertoire courant de la manière suivante :
Mon nom de connexion est : doum
Mon répertoire courant est : /home/doum
#!/bin/sh
echo -n " Mon nom de connexion est:"
logname
echo -n " Mon répertoire courant est: $HOME"
52
GANDHI
Programmation Shell
III. LES VARIABLES
Il n’y est pas de langage sans variable. Une variable sert à mémoriser une information afin
de la réutiliser ultérieurement. Elles sont créées par le programmeur au moment où il en a besoin.
Il n'a pas besoin de les déclarer d'un type particulier et peut en créer quand il veut, où il veut.
Leur nom est représenté par une suite de caractères commençant impérativement par une lettre ou le
caractère _ (souligné ou underscore) et comportant ensuite des lettres, des chiffres ou le caractère
souligné. Il ne doit pas correspondre à un des mots clefs du Shell.
Leur contenu est interprété exclusivement comme du texte. Il n'existe donc pas, en Bourne Shell,
d'instruction d'opération sur des variables ou sur du nombre (addition, soustraction, etc.). Il n'est pas
non plus possible d'avoir des variables dimensionnées (tableaux). Mais cela est possible en
Korn Shell et Bourne Again Shell (et Shell descendants).
Les variables peuvent être classées en trois groupes :
- les variables utilisateur (ex : a, valeur)
- les variables prédéfinies du Shell (ex : PS1, PATH, REPLY, IFS)
- les variables prédéfinies de commandes Unix (ex : TERM).
II.1 Les variables simples ou variables utilisateurs :
1.1 Nomenclature
Un nom de variable obéit à certaines règles :
a) Il peut être composé de lettres minuscules, majuscules, de chiffres, de caractères de soulignement
b) Le premier caractère ne peut pas être un chiffre
c) Le taille d’un nom est en principe illimité (il ne faut pas abuser non plus)
d) Les conventions veulent que les variables utilisateur soient en minuscules pour les différencier
des variables système. Au choix de l’utilisateur.
1.2. Déclaration et affectation
Une variable est déclarée dès qu’une valeur lui est affectée. L’affectation est effectuée avec le signe
«=», sans espace avant ou après le signe.
var=Bonjour
On peut aussi créer des variables vides. Celle-ci existera mais sans contenu.
var=
NB : C'est la seule syntaxe du Shell qui ne veuille pas d'espace dans sa
structure sous peine d'avoir une erreur lors de l'exécution.
Dans le cas où on voudrait entrer une chaîne avec des espaces dans la variable, il faut alors encadrer
la chaîne par des guillemets simples ou doubles. A partir du moment où elle a été affectée, une
variable se met à exister dans la mémoire, même si elle a été affectée avec "rien".
52
GANDHI
Programmation Shell
Une variable peut contenir des caractères spéciaux, le principal étant l’espace. Mais
$ c=Salut les copains
les: not found
$ echo $c
Ne marche pas. Pour cela il faut soit verrouiller les caractères spéciaux un par un, soit de les mettre
entre guillemets ou apostrophes.
c=Salut\ les\ Copains # Solution lourde
c="Salut les copains" # Solution correcte
c=’Salut les copains’ # Solution correcte
La principale différence entre les guillemets et les apostrophes est l’interprétation des variables et
des substitutions. "et' se verrouillent mutuellement.
Exemple :
$ a=soundiata
$ b=keita
$ c="$a $b a conquis le manding"
$ d=’$a $b a conquis le manding’
$ echo $c
Soundiata keita a conquis le manding
$ echo $d
$a $b a conquis le manding
$ echo "Unix c’est top"
Unix c’est top
$ echo ’Unix "trop bien"’
Unix "trop bien"
1.4. La saisie en interactif
Lorsque le programmeur désire demander une information ponctuelle à celui qui utilise le
programme, il utilise l’instruction read
Syntaxe :
read [var1 var2 …]
Si aucune variable n'est demandée, la chaîne saisie sera stockée dans la variable interne "$REPLY"
L’option –p de read affiche une chaine d’appel avant d’effectuer la lecture ;
Syntaxe :
read –p chaîne_d_appel [ var … ]
Exemple1 :
52
GANDHI
Programmation Shell
$ read -p "Entrez votre prenom : " prenom
Entrez votre prenom : Naby
$
$ echo $prenom
Naby
$
Remarques sur la commande interne read
- S’il y a moins de variables que de mots dans la ligne lue, le Shell affecte le premier mot a la
première variable, le deuxième mot a la deuxième variable, etc., la dernière variable reçoit tous les
mots restants.
Exemple2:
$ read a b c
Un bon jour coucou
$
$ echo $a
Un
$ echo $c
jour coucou
$
- S’il y a davantage de variables que de mots dans la ligne lue, chaque variable reçoit un mot et
après épuisement de ces derniers, les variables excédentaires sont vides (c.-à-d. initialisées a la
valeur null).
Exemple3:
$ read a b
Un
$
$ echo $a
Un
$
$ echo $b
=> valeur null
$
Exercice 1 : Ecrire un programme shell exoread1 qui affiche le message "Entrez un mot : ", lit le
mot saisi par l'utilisateur puis affiche ce mot deux fois sur la même ligne comme.
Exemple :
Entrez un mot : toto
toto toto
$
Exercice 2 : Ecrire un programme Shell exoread2 qui demande à l'utilisateur de saisir une suite de
mots constituée d'au moins trois mots et qui affiche sur la même ligne le premier et le troisième mot
saisis.
Exemple:
$ exoread2
Entrez une suite de mots : un petit coucou de Mousto
un coucou
$
1.5. La substitution
On peut utiliser des séquenceurs spéciaux pour modifier la manière dont le Shell va renvoyer le
contenu de ou des variables demandées.
a) Tous types de Shell
52
GANDHI
Programmation Shell
${var} : renvoie le contenu de "$var". Il sert à isoler le nom de la variable par rapport au contexte
de son utilisation. Ceci évite les confusions entre ce que l'utilisateur désire "${prix}F" (variable
"prix" suivi du caractère "F") et ce que le Shell comprendrait si on écrivait simplement "$prixF"
(variable "prixF").
${var-texte} : renvoie le contenu de la variable "var" si celle-ci est définie (existe en mémoire) ;
sinon renvoie le texte "texte".
${var:-texte} : renvoie le contenu de la variable "var" si celle-ci est définie et non vide ; sinon
renvoie le texte "texte".
${var+texte} : renvoie le texte "texte" si la variable "var" est définie ; sinon ne renvoie rien
${var:+texte} : renvoie le texte "texte" si la variable "var" est définie et non-vide ; sinon ne
renvoie rien
${var?texte} : renvoie le contenu de la variable "var" si celle-ci est définie ; sinon affiche le texte
"texte" comme message d'erreur (implique donc l'arrêt du script).
${var:?texte} : renvoie le contenu de la variable "var" si celle-ci est définie et non-vide ; sinon
affiche le texte "texte" (comme "${var:-texte}") comme message d'erreur (implique donc l'arrêt du
script).
${var=texte} : renvoie le contenu de la variable "var" si celle-ci est définie, sinon affecte le texte
"texte" à la variable "var" avant de renvoyer son contenu.
${var:=texte} : renvoie le contenu de la variable "var" si celle-ci est définie et non-vide, sinon
affecte le texte "texte" à la variable "var" avant de renvoyer son contenu.
b) Uniquement en Bourne Again Shell (et shells descendants)
${!var} : utilise le contenu de la variable "var" comme un nom de variable et renvoie le contenu
de cette dernière (permet donc de simuler un pointeur).
${var:x:y} : renvoie les "y" caractères de la variable "var" à partir du caractère n° "x" (attention;
le premier caractère d'une variable porte le n° "0"). Si la variable est un tableau, renvoie alors les
"y" éléments du tableau "var" à partir de l'élément n° "x".
${var:x} : renvoie la fin de la variable "var" à partir du caractère n° "x" (attention; le premier
caractère d'une variable porte le n° "0"). Si la variable est un tableau, renvoie alors les derniers
éléments du tableau "var" à partir de l'élément n° "x"
${var/texte1/texte2} : renvoie le contenu de "var" mais en lui remplaçant la première occurrence
de la chaîne "texte1" par la chaîne "texte2".
${var//texte1/texte2} : renvoie le contenu de "var" mais en lui remplaçant chaque occurrence de
la chaîne "texte1" par la chaîne "texte2".
Remarque
L'imbrication de séquenceurs est possible. Ainsi, la syntaxe "${var1:-${var2:-texte}}" renvoie le
contenu de la variable "var1" si celle-ci est définie et non nulle ; sinon, renvoie le contenu de la
variable "var2" si celle-ci est définie et non nulle ; sinon renvoie le texte "texte".
readonly
52
GANDHI
Programmation Shell
Cette commande, lorsqu'elle est employée sur une variable, la verrouille contre toute modification
et/ou suppression, volontaire ou accidentelle. Une fois verrouillée, la variable ne disparaîtra qu'à la
mort du processus qui l'utilise.
Employée sans argument, l'instruction "readonly" donne la liste de toutes les variables protégées
Suppression
Syntaxe :
Remarque : Une variable en lecture seule même vide est figée. Il n’existe aucun moyen de
la replacer en écriture et de la supprimer, sauf à quitter le Shell.
Exemple:
$ a=soundiata
$ b=keita
$ echo $a $b
soundiata keita
$ unset b
$ echo $a $b
soundiata
$ readonly a
$ a=Nestor
bash: a: readonly variavle
$ unset a
bash: a: readonly variavle
1.5. Exportation
Syntaxe :
Par défaut une variable n’est accessible que depuis le Shell où elle a été définie.
$ a=soundiata
$ echo ’echo "a=$a"’ > voir_a.sh
$ chmod u+x voir_a.sh
$ ./voir_a.sh
a=
La commande export permet d’exporter une variable de manière à ce que son contenu soit visible
par les scripts et autres sous-Shell.
52
GANDHI
Programmation Shell
La commande export permet d’exporter une variable de manière à ce que son contenu soit visible
par les scripts et autres sous-Shell. Lorsqu’un script Shell est lancé depuis l'environnement d'un
utilisateur, ce script commence son exécution avec une zone mémoire vierge qui lui est propre. Il ne
connaît donc, par défaut, aucune des variables de l'environnement qui lui a donné naissance
(environnement "père").
Pour qu'un processus "père" puisse faire connaître une variable à un processus "fils", il doit
l'exporter avec la commande "export var". Ceci fait, la variable exportée depuis un environnement
particulier sera connue de tous les processus "fils" ; et de tous les processus "fils" des "fils", etc.
Cependant, modifier le contenu d'une variable dans un processus quelconque ne reporte pas cette
modification dans les environnements supérieurs. Dans la même optique, il n'y a aucun moyen
simple pour renvoyer une variable quelconque d'un processus vers un processus parent.
Employée seule, la commande "export" donne la liste de toutes les variables qui ont été exportées.
$ export a
$ ./voir_a.sh
a=soundiata
$ echo ’a=Nestor ; echo "a=$a"’ >> voir_a.sh
$ ./voir_a.sh
a=soundiata
a=Nestor
$ echo $a
Soundiata
1.6. Accolades
Les accolades de base « {} » permettent d’identifier le nom d’une variable. Imaginons la variable
fichier contenant le nom de fichier 'liste'. On veut copier liste1 en liste2.
$ fichier=liste
$ cp $fichier2 $fichier1
usage: cp [-fhip] [--] source_file destination_file
ou: cp [-fhip] [--] source_file ... destination_directory
ou: cp [-fhip] [-R | -r] [--]
[source_file | source_directory] ...
destination_directory
Ça ne fonctionne pas car ce n’est pas $fichier qui est interprété mais plutôt $fichier1 et
$fichier2 qui n’existent pas.
$ cp ${fichier}2 ${fichier}1
Dans ce cas, cette ligne équivaut à
$ cp liste2 liste1
Les accolades indiquent que fichier est un nom de variable.
1.7. Accolades et remplacement conditionnel
Les accolades disposent d’une syntaxe particulière.
{variable:Remplacement}
Selon la valeur ou la présence de la variable, il est possible de remplacer sa valeur par
une autre.
52
GANDHI
Programmation Shell
$ echo $nom
$ echo ${nom:-Naby}
Naby
$ echo $nom
$ echo ${nom:=Naby}
Naby
$ echo $nom
Naby
$ echo ${nom:+"Valeur définie"}
Valeur définie
$ unset nom
$ echo ${nom:?Variable absente ou non définie}
nom: Variable absente ou non définie
$ nom=Naby
$ echo ${nom:?Variable absente ou non définie}
Naby
II.2 variables système
En plus des variables que l’utilisateur peux définir lui-même, le shell est lancé avec un
certain nombre de variables prédéfinies utiles pour un certain nombre de commandes et
accessibles par l’utilisateur. Le contenu de ces variables système peut être modifié mais il
faut alors faire attention car certaines ont une incidence directe sur le comportement du
système.
52
GANDHI
Programmation Shell
En plus de ces variables voici d’autres non moins important en fonction de certains Shell
particuliers
PWD Répertoire courant (uniquement en "Korn Shell" ou "Bourne Again Shell" et
shells descendants)
OLDPWD Répertoire dans lequel on était avant notre dernier changement de répertoire
(uniquement en "Korn Shell" ou "Bourne Again Shell" et shells descendants)
REPLY Chaîne saisie par l'utilisateur si la commande "read" a été employée sans
52
GANDHI
Programmation Shell
argument (uniquement en "Korn Shell" et "Bourne Again Shell" et shells
descendants)
Exemple :
Écrivez une ligne de commande qui affiche "Bonjour tout le monde, mon nom d'utilisateur est nom
d’utilisateur, mon répertoire privé se trouve en référence absolu du répertoire privé, et mon shell
est nom du Shell
echo "Bonjour tout le monde, mon nom d'utilisateur est $USER,
mon répertoire prive se trouve en $HOME et mon shell est $SHELL."
II.3 Variables spéciales
Il s’agit de variables accessibles uniquement en lecture et dont le contenu est généralement
contextuel.
Exemple :
$ echo $$
23496
$ grep memoire liste
$ echo $?
1
$ grep souris liste
souris optique 30 15
$ echo $?
0
$ ls -lR >toto.txt 2<&1 &
26675
$ echo $!
26675
II.4 Paramètres de position
Les paramètres de position sont aussi des variables spéciales utilisées lors d’un passage
de paramètres à un script.
4.1 Description
52
GANDHI
Programmation Shell
Exemple :
$ cat >param.sh
#!/bin/sh
echo "Nom : $0"
echo "Nombre de parametres : $#"
echo "Parametres : 1=$1 2=$2 3=$3"
echo "Liste : $*"
echo "Elements : $@"
$ param.sh riri fifi loulou
Nom : ./param.sh
Nombre de parametres : 3
Parametres : 1=riri 2=fifi 3=loulou
Liste : riri fifi loulou
Elements : riri fifi loulou
La différence entre $@ et $* ne saute pas aux yeux. Reprenons l' exemple précédent avec
une petite modification :
$ param.sh riri "fifi loulou"
Nom : ./param.sh
Nombre de parametres : 2
Parametres : 1=riri 2=fifi loulou 3=
Liste : riri fifi loulou
Elements : riri fifi loulou
Cette fois-ci il n’y a que deux paramètres de passés. Pourtant les listes semblent
visuellement identiques. En fait si la première contient bien
"riri fifi loulou"
La deuxième contient
"riri" "fifi loulou"
Soit bien deux éléments. Dans le premier exemple nous avions
"riri" "fifi" "loulou"
4.2 Redéfinition des paramètres
Outre le fait de lister les variables, la commande set permet de redéfinir le contenu des
variables de position. Avec
set valeur1 valeur2 valeur3 ...
$1 prendra comme contenu valeur1, $2 valeur2 et ainsi de suite.
$ cat >param2.sh
#!/bin/sh
echo "Avant :"
echo "Nombre de parametres : $#"
echo "Parametres : 1=$1 2=$2 3=$3 4=$4"
echo "Liste : $*"
set alpha fode sylla bouba
echo "apres set alpha fode sylla bouba"
echo "Nombre de parametres : $#"
echo "Parametres : 1=$1 2=$2 3=$3 4=$4"
echo "Liste : $*"
$ ./param2.sh riri fifi loulou donald picsou
Avant :
Nombre de parametres : 5
Parametres : 1=riri 2=fifi 3=loulou 4=donald
Liste : riri fifi loulou donald picsou
apres set alpha fode sylla bouba
Nombre de parametres : 4
Parametres : 1=alpha 2=fode 3=sylla 4=bouba
Liste : alpha fode sylla bouba
52
GANDHI
Programmation Shell
4.3 Réorganisation des paramètres
La commande shift est la dernière commande permettant de modifier la structure des
paramètres de position. Un appel simple décale tous les paramètres d’une position en
supprimant le premier : $2 devient $1, $3 devient $2 et ainsi de suite. Le $1 originel
disparaît. $#, $* et $@ sont redéfinis en conséquence.
La commande shift suivie d’une valeur n effectue un décalage de n éléments. Ainsi avec
shift 4
$5 devient $1, $6 devient $2, ...
$ cat > param3.sh
#!/bin/sh
set alpha fode sylla bouba
echo "set alpha fode sylla bouba "
echo "Nombre de parametres : $#"
echo "Parametres : 1=$1 2=$2 3=$3 4=$4"
echo "Liste : $*"
shift
echo "Après un shift"
echo "Nombre de parametres : $#"
echo "Parametres : 1=$1 2=$2 3=$3 4=$4"
echo "Liste : $*"
$ ./param3.sh
set alpha fode sylla bouba
Nombre de parametres : 4
Parametres : 1=alpha 2=fode 3=sylla 4=bouba
Liste : alpha fode sylla bouba
Après un shift
Nombre de parametres : 3
Parametres : 1=fode 2=sylla 3=bouba 4=
Liste : fode sylla bouba
II.5 Sortie de script
La commande exit permet de mettre fin à un script. Par défaut la valeur retournée est 0
(pas d’erreur) mais n' importe quelle autre valeur de 0 à 255 peut être précisée. On
récupère la valeur de
sortie par la variable $?.
$ exit 1
II.6 Environnement du processus
En principe seules les variables exportées sont accessibles par un processus fils. Si on
souhaite
visualiser l’environnement lié à un fils (dans un script par exemple) on utilise la commande
env.
$env
GENT_INFO=/tmp/seahorse-n15EPL/S.gpg-agent:3317:1
SHELL=/bin/bash
DESKTOP_STARTUP_ID=
TERM=xterm
GTK_RC_FILES=/etc/gtk/gtkrc:/home/client/.gtkrc-1.2-gnome2
WINDOWID=37748813
USER=client
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;
01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.svgz=01;31:*.arj=01;31
:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.bz2=01;31:*.b
52
GANDHI
Programmation Shell
z=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.
cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;3
5:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.mng=
01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;
35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmv
b=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.aac
=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36
:*.ra=00;36:*.wav=00;36:
SSH_AUTH_SOCK=/tmp/keyring-EbBkjw/ssh
GNOME_KEYRING_SOCKET=/tmp/keyring-EbBkjw/socket
SESSION_MANAGER=local/client:/tmp/.ICE-unix/3262
USERNAME=client
DESKTOP_SESSION=default
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
GDM_XSERVER_LOCATION=local
PWD=/home/client
LANG=fr_FR.UTF-8
GNOME_KEYRING_PID=3261
GDM_LANG=fr_FR.UTF-8
GDMSESSION=default
HISTCONTROL=ignoreboth
HOME=/home/client
SHLVL=1
GNOME_DESKTOP_SESSION_ID=Default
LOGNAME=client
XDG_DATA_DIRS=/usr/local/share/:/usr/share/:/usr/share/gdm/
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-UYIYcNfw7C,guid=aa4f92e8cbfecea82281d82c5100edf3
WINDOWPATH=7
DISPLAY=:0.0
COLORTERM=gnome-terminal
XAUTHORITY=/home/client/.Xauthority
_=/usr/bin/env
OLDPWD=/tmp
La commande env permet de redéfinir aussi l’environnement du processus à lancer. Cela
peut être utile lorsque le script doit accéder à une variable qui n’est pas présente dans
l’environnement du père, ou qu’on ne souhaite pas exporter. La syntaxe est
env var1=valeur var2=valeur ... commande
Si la première option est le signe « - » alors c’est tout l’environnement existant qui est
supprimé pour être remplacé par les nouvelles variables et valeurs.
$ unset a
$ ./voir_a.sh
a=
$ env a=jojo ./voir_a.sh
a=jojo
$ echo a=$a
a=
II.7 Substitution de commande
Le mécanisme de substitution permet de placer le résultat de commandes simples ou
complexes dans une variable. On place les commandes à exécuter entre des accents
graves « ‘ ». (Alt Gr + 7).
$ mon_unix=‘uname‘
$ echo ${mon_unix}
Linux
52
GANDHI
Programmation Shell
$ machine=‘uname -a | cut -d" " -f5‘
$ echo $machine
SMP
Attention, seul le canal de sortie standard est affecté à la variable. Le canal d’erreur
standard sort toujours vers l’écran.
II.8 Tests de conditions
La commande test permet d’effectuer des tests de conditions. Le résultat est récupérable
par la variable $? (code retour). Si ce résultat est 0 alors la condition est réalisée.
8.1 tests sur chaîne
test -z "variable" : zéro, retour OK si la variable est vide (ex test -z "$a")
test -n "variable" : non zéro, retour OK si la variable n’est pas vide (texte
quelconque)
test "variable" = chaîne : OK si les deux chaînes sont identiques
test "variable" != chaîne : OK si les deux chaînes sont différentes
$ a=
$ test -z "$a" ; echo $?
0
$ test -n "$a" ; echo $?
1
$ a=Doum
$ test "$a" = Doum ; echo $?
8.1 tests sur valeurs numériques
Les chaînes à comparer sont converties en valeurs numériques. La syntaxe est
test valeur1 option valeur2
et les options sont les suivantes :
$ a=10
$ b=20
$ test "$a" -ne "$b" ; echo $?
0
$ test "$a" -ge "$b" ; echo $?
1
$ test "$a" -lt "$b" && echo "$a est inferieur a $b"
10 est inferieur a 20
8.3 tests sur les fichiers
La syntaxe est
test option nom_fichier
et les options sont les suivantes :
52
GANDHI
Programmation Shell
$ ls -l
-rw-r--r-- 1 gandhi serveur 1392 Aug 14 15:55 dump.log
lrwxrwxrwx 1 gandhi serveur 4 Aug 14 15:21 lien_fic1 -> fic
lrwxrwxrwx 1 gandhi serveur 4 Aug 14 15:21 lien_fic2 -> fic
-rw-r--r-- 1 gandhi serveur 234 Aug 16 12:20 liste1
-rw-r--r-- 1 gandhi serveur 234 Aug 13 10:06 liste2
-rwxr--r-- 1 gandhi serveur 288 Aug 19 09:05 param.sh
-rwxr--r-- 1 gandhi serveur 430 Aug 19 09:09 param2.sh
-rwxr--r-- 1 gandhi serveur 292 Aug 19 10:57 param3.sh
drwxr-xr-x 2 gandhi serveur 8192 Aug 19 12:09 rep1
-rw-r--r-- 1 gandhi serveur 1496 Aug 14 16:12 resultat.txt
-rw-r--r-- 1 gandhi serveur 1715 Aug 16 14:55 toto.txt
-rwxr--r-- 1 gandhi serveur 12 Aug 16 12:07 voir_a.sh
$ test -f lien_fic1 ; echo $?
1
$ test -x dump.log ; echo $?
1
$ test -d rep1 ; echo $?
0
8.4 tests combinés par critères ET OU NON
On peut effectuer plusieurs tests avec une seule instruction. Les options de combinaisons
sont les mêmes que pour la commande find.
$ ./param4.sh
Aucun parametre; set alpha fode sylla bouba
Nombre de parametres : 4
Parametres : 1=alpha 2=fode 3=sylla 4=bouba
Liste : alpha fode sylla bouba
10. Choix multiples case
La commande case esac permet de vérifier le contenu d’une variable ou d’un résultat de
manière multiple.
case Valeur in
Modele1) Commandes ;;
Modele2) Commandes ;;
*) action_defaut ;;
esac
Le modèle est soit un simple texte, soit composé de caractères spéciaux. Chaque bloc de
commandes lié au modèle doit se terminer par deux points-virgules. Dès que le modèle
est vérifié, le bloc de commandes correspondant est exécuté. L’étoile en dernière position
(chaîne variable) est l’action par défaut si aucun critère n’est vérifié.
52
GANDHI
Programmation Shell
Exemple :
$ cat > case1.sh
#!/bin/sh
if [ $# -ne 0 ]
then
echo "$# parametres en ligne de commande"
else
echo "Aucun parametre; set alpha fode sylla bouba"
exit 1
fi
case $1 in
a*)
echo "Commence par a"
;;
b*)
echo "Commence par b"
;;
fic[123])
echo "fic1 fic2 ou fic3"
;;
*)
echo "Commence par n’importe"
;;
esac
exit 0
$ ./case1.sh "au revoir"
Commence par a
$ ./case1.sh bonjour
Commence par b
$ ./case1.sh fic2
fic1 ou fic2 ou fic3
$ ./case1.sh erreur
Commence par n’importe
11. Saisie de l’utilisateur
La commande read permet à l’utilisateur de saisir une chaîne et de la placer dans une ou
plusieurs variable. La saisie est validée par entrée.
read var1 [var2 ...]
Si plusieurs variables sont précisées, le premier mot ira dans var1, le second dans var2, et
ainsi de suite. S’il y a moins de variables que de mots, tous les derniers mots vont dans la
dernière variable.
Exemple :
$ cat > read.sh
#!/bin/sh
echo "Continuer (O/N) ? \c"
read reponse
echo "reponse=$reponse"
case $reponse in
O)
52
GANDHI
Programmation Shell
echo "Oui, on continue"
;;
N)
echo "Non, on s'arrête"
exit 0
;;
*)
echo "Erreur de saisie (O/N)"
exit 1
;;
esac
echo "Vous avez continue. Tapez deux mots ou plus :\c"
read mot1 mot2
echo "mot1=$mot1\nmot2=$mot2"
exit 0
$ ./read.sh
Continuer (O/N) ? O
reponse=O
Oui, on continue
Vous avez continue. Tapez deux mots ou plus :salut les amis
mot1=salut
mot2=les amis
12. Les boucles
Elles permettent la répétition d’un bloc de commandes soit un nombre limité de fois, soit
conditionnellement. Toutes les commandes à exécuter dans une boucle se placent entre
les commandes do et done.
12. 1 Boucle for
La boucle for ne se base pas sur une quelconque incrémentation de valeur mais sur une
liste de valeurs, de fichiers ...
for var in liste
do
commandes à exécuter
done
La liste représente un certain nombre d’éléments qui seront successivement attribuées à
var1.
12. .1.1 Avec une variable
$ cat >for1.sh
#!/bin/sh
for params in $@
do
echo "$params"
done
$ ./for1.sh test1 test2 test3
test1
test2
test3
12. 1.2 Liste implicite
Si on ne précise aucune liste à for, alors c' est la liste des paramètres qui est implicite.
Ainsi le script
précédent aurait pu ressembler à :
for params
52
GANDHI
Programmation Shell
do
echo "$params"
done
12. 1.3 Avec une liste d’éléments explicite :
Exemple:
$ cat >for2.sh
#!/bin/sh
for params in liste liste2
do
ls -l $params
done
$ ./for2.sh
-rw-r--r-- 1 gandhi serveur 234 Aug 19 14:09 liste
-rw-r--r-- 1 gandhi serveur 234 Aug 13 10:06 liste2
12 .1.4 Avec des critères de recherche sur nom de fichiers :
Exemple :
$ cat > for3.sh
#!/bin/sh
for params in *
do
echo "$params \c"
type_fic=‘ls -ld $params | cut -c1‘
case $type_fic in
-) echo "Fichier normal" ;;
d) echo "Repertoire" ;;
b) echo "mode bloc" ;;
l) echo "lien symbolique" ;;
c) echo "mode caractere" ;;
*) echo "autre" ;;
esac
done
$ ./for3.sh
case1.sh Fichier normal
dump.log Fichier normal
for1.sh Fichier normal
for2.sh Fichier normal
for3.sh Fichier normal
lien_fic1 lien symbolique
lien_fic2 lien symbolique
liste Fichier normal
liste1 Fichier normal
liste2 Fichier normal
param.sh Fichier normal
param2.sh Fichier normal
param3.sh Fichier normal
param4.sh Fichier normal
read.sh Fichier normal
rep1 Repertoire
resultat.txt Fichier normal
toto.txt Fichier normal
voir_a.sh Fichier normal
12.1.5 Avec une substitution de commande :
Exemple :
52
GANDHI
Programmation Shell
$ cat for4.sh
#!/usr/bin/sh
echo "Liste des utilisateurs dans /etc/passwd"
for params in ‘cat /etc/passwd | cut -d: -f1‘
do
echo "$params "
done
$ ./for4.sh
Liste des utilisateurs dans /etc/passwd
root
nobody
nobodyV
daemon
bin
uucp
uucpa
auth
cron
lp
tcb
adm
ris
carthic
ftp
stu
...
12 .2 Boucle while
La commande while permet une boucle conditionnelle « tant que ». Tant que la condition
est réalisée, le bloc de commande est exécuté. On sort si la condition n' est plus valable.
while condition
do
commandes
done
ou
while
bloc d’instructions formant la condition
do
commandes
done
Exemple :
$ cat >while1.sh
#!/bin/sh
while
echo "Chaine ? \c"
read nom
[ -z "$nom" ]
do
echo "ERREUR : pas de saisie"
done
echo "Vous avez saisi : $nom"
Exemple : une lecture d’un fichier ligne à ligne :
#!/bin/sh
cat toto.txt | while read line
52
GANDHI
Programmation Shell
do
echo "$line"
done
ou
#!/usr/bin/sh
while read line
do
echo "$line"
done < toto.txt
12. 3 Boucle until
La commande until permet une boucle conditionnelle « jusqu' à ». Dès que la condition
est réalisée, on sort de la boucle.
until condition
do
commandes
done
ou
until
bloc d’instructions formant la condition
do
commandes
done
12. .4 seq
La commande seq permet de sortir une séquence de nombres, avec un intervalle
éventuel.
seq [debut] [increment] fin
Exemple :
$ seq 5
1
2
3
4
5
$ seq -2 3
-2
-1
0
1
2
3
$ seq 0 2 10
0
2
4
6
8
10
12. 5 true et false
La commande true ne fait rien d’autre que de renvoyer 0. La commande false renvoie
toujours 1.
De cette manière il est possible de faire des boucles sans fin. La seule manière de sortir
de ces boucles est un exit ou un break.
while true
do
commandes
exit / break
52
GANDHI
Programmation Shell
done
12.6 break et continue
La commande break permet d’interrompre une boucle. Dans ce cas le script continue
après la commande done. Elle peut prendre un argument numérique indiquant le nombre
de boucles à sauter, dans le cadre de boucles imbriquées (rapidement illisible).
while true
do
echo "Chaine ? \c"
read a
if [ -z "$a" ]
then
break
fi
done
La commande continue permet de relancer une boucle et d’effectuer un nouveau
passage. Elle peut prendre un argument numérique indiquant le nombre de boucles à
relancer (on remonte de n boucles). Le script redémarre à la commande do.
13. Les fonctions
Les fonctions sont des bouts de scripts nommés, directement appelés par leur nom,
pouvant accepter des paramètres et retourner des valeurs. Les noms de fonctions suivent
les mêmes règles que les variables sauf qu’elles ne peuvent pas être exportées.
nom_fonction ()
{
commandes
return
}
Les fonctions peuvent être soit tapées dans votre script courant, soit dans un autre fichier
pouvant
être inclus dans l’environnement. Pour cela :
. nomfic
Le point suivi d’un nom de fichier charge son contenu (fonctions et variables dans
l’environnement courant.
La commande return permet d’affecter une valeur de retour à une fonction. Il ne faut
surtout par utiliser la commande exit pour sortir d’une fonction, sinon on quitte le script.
Exemple :
$ cat >fonction
ll ()
{
ls -l $@
}
li ()
{
ls -i $@
}
$ . fonction
$ li
252 case1.sh 326 for4.sh 187 param.sh 897 resultat.txt
568 dump.log 409 lien_fic1 272 param2.sh 991 toto.txt
286 fonction 634 lien_fic2 260 param3.sh 716 voir_a.sh
235 for1.sh 1020 liste 42 param4.sh 1008 while1.sh
909 for2.sh 667 liste1 304 read.sh
789 for3.sh 1006 liste2 481 rep1
14. expr
La commande expr permet d’effectuer des calculs sur des valeurs numériques, des
comparaisons, et de la recherche dans des chaînes de texte.
52
GANDHI
Programmation Shell
Exemple :
$ expr 7 + 3
10
$ expr 7 \* 3
21
$ a=`expr 13 – 10`
$ echo $a
3
$ cat expr1.sh
#!/bin/sh
cumul=0
compteur=0
nb_boucles=10
while [ "$compteur" -le "$nb_boucles" ]
do
cumul=`expr $cumul + $compteur`
echo "cumul=$cumul, boucle=$compteur"
compteur=`expr $compteur + 1`
done
$ ./expr1.sh
cumul=0, boucle=0
cumul=1, boucle=1
cumul=3, boucle=2
cumul=6, boucle=3
cumul=10, boucle=4
cumul=15, boucle=5
cumul=21, boucle=6
cumul=28, boucle=7
cumul=36, boucle=8
cumul=45, boucle=9
cumul=55, boucle=10
$ expr "Jules Cesar" : ".*"
11
15. Une variable dans une autre variable
Exemple :
$ a=Diallo
$ b=a
$ echo $b
a
52
GANDHI
Programmation Shell
Comment afficher le contenu de a et pas simplement a ? En utilisant la commande eval.
Cette commande située en début de ligne essaie d’interpréter, si possible, la valeur d’une
variable précédée par deux « $ », comme étant une autre variable.
$ eval echo \$$b
Diallo
16. Traitement des signaux
La commande trap permet de modifier le comportement du script à la réception d’un
signal.
17. Commande « : »
La commande « : » est généralement totalement inconnue des utilisateurs Unix. Elle
retourne toujours la valeur 0 (réussite). Elle peut donc être utilisée pour remplacer la
commande true dans une boucle
Exemple :
while :
do
...
done
Cette commande placée en début de ligne, suivie d’une autre commande, traite la
commande et ses arguments mais ne fait rien, et retourne toujours 0. Elle peut être utile
pour tester les variables.
$ : ls
$ : ${X:?"Erreur"}
X : Erreur
18. Délai d’attente
La commande sleep permet d’attendre le nombre de secondes indiqués. Le script est
interrompu durant ce temps. Le nombre de secondes et un entier compris entre 0 et 4
milliards (136 ans).
$ sleep 10
III - Les alias
Un alias est une substitution d’une commande par un raccourci. L’alias est prioritaire sur
les fonctions, commandes internes et commandes externes. Il est possible d’y substituer
du texte.
alias nom_alias=commande_ou_texte
$ alias deltree=’rm -rf’
$ deltree rep1
La substitution ne s’effectue que si l’alias est la première commande ou si le texte de
l’alias se termine par un espace.
$ alias list=ls -l ’
$ alias home=’/tmp/seb’
$ list home
total 22
-rwxr--r-- 1 gandhi serveur 327 Aug 19 13:31 case1.sh
-rw-r--r-- 1 gandhi serveur 1392 Aug 14 15:55 dump.log
52
GANDHI
Programmation Shell
-rwxr--r-- 1 gandhi serveur 200 Aug 19 15:58 expr1.sh
-rw-r--r-- 1 gandhi serveur 42 Aug 19 15:43 fonction
-rwxr--r-- 1 gandhi serveur 57 Aug 19 14:06 for1.sh
-rwxr--r-- 1 gandhi serveur 66 Aug 19 14:09 for2.sh
-rwxr--r-- 1 gandhi serveur 285 Aug 19 14:32 for3.sh
-rwxr--r-- 1 gandhi serveur 133 Aug 19 14:37 for4.sh
lrwxrwxrwx 1 gandhi serveur 4 Aug 14 15:21 lien_fic1 -> fic1
lrwxrwxrwx 1 gandhi serveur 4 Aug 14 15:21 lien_fic2 -> fic2
...
Sans paramètre, c' est la liste des alias q
$ alias
autoload=’typeset -fu’
cat=/usr/bin/cat
command=’command ’
deltree=’rm -rf’
functions=’typeset -f’
grep=/usr/bin/grep
hash=’alias -t -’
history=’fc -l’
home=/tmp/seb
integer=’typeset -i’
list=’ls -l ’
local=typeset
ls=/usr/bin/ls
nohup=’nohup ’
r=’fc -e -’
rm=/usr/bin/rm
stop=’kill -STOP’
suspend=’kill -STOP $$’
type=’whence -v’
ces alias marche jusqu’à ce que vous éteignez ou redémarrez votre machine. Ainsi pour
fixer votre alias, vous éditerez le fichier .bashrc et placé votre alias après les lignes des
alias déjà prédéfini
52
GANDHI
Programmation Shell
IV - PARTICULARITES DU KORN SHELL
Si le Bourne Shell est un shell POSIX présent et standard sur tous les UNIX, le Korn Shell,
apparu dans sa version moderne sous System V release 4 devient aujourd'hui un standard
de fait. Le Korn Shell ou ksh est entièrement compatible avec le Bourne Shell (scripts
exécutables sans modification) et le Bourne Again Shell (bash sous Linux). Ksh est
présent sous Linux avec le nom pdksh.
Parmi les nouvelles possibilités :
Les alias
Possibilité de typer les variables, gestion des tableaux et des chaînes
Commandes supplémentaires
Gestion des jobs
Le fichier de configuration par défaut est le fichier .profile. On peut y placer ses définitions
de variables, alias, ...
1. Historique et répétition
On peut accéder à l’historique des commandes avec la commande fc. Cette
commande permet aussi de rappeler une ligne précise ou d’en modifier le contenu. La
taille de l’historique se contrôle avec la valeur de la variable HISTSIZE (HISTSIZE=200
prendra en compte les 200 dernières commandes).
Exemple :
$ fc -l
117 test "$a" -lt "$b"
118 $?
119 exit
120 init 6
121 apt-get install telnet
122 man telnet
123 telnet -u [email protected]
124 telnet 192.168.1.10
125 scp -S ssh gandhi@serveur:/home/gandhi/Destop/
126 ls
127 apt-get install pdksh
128 *apt-cache sear
129 apt-cache search ksh
130 apt-get install csh
131 fc -l
132 clear
2. Modifications concernant les variables
1.1 Variables système
Voici quelques nouvelles variables système.
52
GANDHI
Programmation Shell
Il est maintenant possible d’obtenir la longueur d’une chaîne autrement qu' avec la
commande expr. On utilise le caractère « # »
$ a=Naby
$ echo "Longueur du mot $a est : ${#a}"
Longueur de Naby : 4
1. 3 Tableaux et champs
Le ksh introduit la gestion des tableaux de variables Deux moyens sont disponibles pour
déclarer un tableau, l’un avec l’utilisation des crochets « [ ] », l’autre avec la commande «
set -A ». Le premier élément est 0 le dernier 1023. Pour accéder au contenu du tableau il
faut mettre la variable ET l’élément entre accolades « {} ».
$ Nom[0]="Moussa"
$ Nom[1]="Rose"
$ Nom[2]="Fifi"
$ echo ${Nom[1]}
Rose
ou
$ set -A Nom Moussa Rose Fifi
$ echo ${nom[2]}
Fifi
Pour lister tous les éléments :
$ echo ${Nom[*]}
Moussa Rose Fifi
Pour connaître le nombre d’éléments
$ echo ${#Nom[*]}
3
Si l’index est une variable, on ne met pas le $ :
$ idx=0
$ echo ${Nom[idx]}
Moussa
1.4 Opérations sur chaînes
Les recherches sur chaînes sont maintenant possibles au sein même de la variable. Le
texte trouvé en fonction de critères est supprimé de la variable.
52
GANDHI
Programmation Shell
${variable<Opérateur>Critère}
Exemple :
$ a="Bonjour les amis"
$ echo ${a#Bon*}
jour les amis
$ echo ${a##Bon*}
La commande typeset propose quelques options intéressantes
$ typeset -u txt1
$ txt1="abcdefg"
ABCDEFG
$ typeset -u txt1
$ echo $txt1
abcdefg
1. 5 Variables typées
Les variables peuvent être typées en entier (integer) avec la commande « typeset -i » le
permet. L’avantage est qu’il devient possible d’effectuer des calculs et des comparaisons
sans passer par expr. La commande let ou « ((...)) » permet des calculs sur variables.
Exemple :
$ typeset -i resultat
$ resultat=6*7
$ echo $resultat
52
GANDHI
Programmation Shell
42
$ resultat=Erreur
ksh: Erreur: bad number
$ resultat=resultat*3
126
$ typeset -i add
$ add=5
$ let resultat=add+5 resultat=resultat*add
$ echo $resultat
50
3. Nouvelle substitution de commande
On peut toujours utiliser les accents pour effectuer une substitution de commandes, mais il
est maintenant plus simple d’utiliser la syntaxe « $(...) ».
$ date_courante=$(date)
$ echo $date_courante
Tue Aug 20 16:07:05 MET DST 2002
4. cd
Nous avons vu deux nouvelles variables nouvelles PWD et OLDPWD. La nouvelle
commande cd permet de les exploiter. « cd - » on retourne dans le catalogue précédent.
$ pwd
/tmp/seb
$ cd ..
$ pwd
/tmp
$ cd -
$ pwd
/tmp/seb
Le tilde permet un raccourci pour le répertoire utilisateur.
$ cd ~rep1
$ pwd
/tmp/seb/rep1
Enfin,
$ cd rep1 rep2
$ pwd
/tmp/seb/rep2
5. Gestion de jobs
Lorsqu' un processus est lancé en tâche de fond, ksh affiche en plus du PID un numéro
entre crochets. Il s’agit d’un numéro de job, incrémenté de 1 à chaque nouveau lancement
si les commandes précédentes ne sont pas terminées. La commande jobs permet
d’obtenir des informations.
$ ls -lR > /toto.txt &
[1] 25994
$ jobs -l
[1] + Running ls -lR / >toto.txt 2>&1 &
Le processus de PID 25994 a été lancé avec le numéro de job 1. Son état actuel est
running (il peut être Done, Stopped, Terminated).
Pour interrompre un processus en premier plan sans le quitter (le passer en stopped mais
pas en terminated) on utilise généralement la séquence Ctrl+Z. Dans ce cas le processus
est stoppé mais pas terminé, et on a accès à la ligne de commande. Pour le relancer en
arrière-plan on utilise la commande bg %n (background, n numéro de job). Pour replacer
52
GANDHI
Programmation Shell
une commande en arrière-plan au premier plan, on utilise la commande fg %n
(foreground, n numéro de job).
$ ls -lR / >toto.txt 2>&1
[1] + Stopped ls -lR / >toto.txt 2>&1
$ bg %1
[1] ls -lR / >toto.txt 2>&1&
$ jobs -l
[1] + 26329 Running ls -lR / >toto.txt 2>&1
$ fg %1
ls -lR / >toto.txt 2>&1
La commande kill dans sa nouvelle syntaxe peut effectuer la même chose.
kill -STOP %1 <-> Ctrl+Z
kill -CONT %1 <-> fg %1
6. Print
La commande print est une extension de la commande echo, et accepte de nouveaux
paramètres en plus de ceux de la commande echo.
8. Options du shell
52
GANDHI
Programmation Shell
La commande set permet d’autres options que vi et emacs. L’option -o active l’option, +o
l’annule.
La commande « set -o » sans rien d’autre affiche la liste des options et leur état.
allexport : toutes les variables déclarées seront automatiquement exportées
bgnice : les processus lancés en tâche de fond ont un facteur nice plus important
et donc tournent avec une priorité moindre
ignoreeof : La combinaison Ctrl+D n’est plus interprétée.
noclobber : la redirection > n' écrase plus le fichier et produit un message d' erreur
s' il existe.
Pour l' écraser tout de même : >|
$ set -o noclobber
$ wc -l toto.txt
378264 toto.txt
$ ls > toto.txt
ksh: toto.txt: file already exists
$ ls >| toto.txt
$ wc -l toto.txt
18 toto.txt
$ set +o noclobber
9. Commande whence
La commande whence indique le type de commande lancée
$ whence -v cd
cd is a shell builtin
$ whence -v test
test is a shell builtin
$ whence -v ls
ls is a tracked alias for /usr/bin/ls
$ whence -v rm
rm is a tracked alias for /usr/bin/rm
$ whence -v echo
echo is a shell builtin
$ whence -v touch
touch is /usr/bin/touch
52
GANDHI
Programmation Shell
incorrecte, une boucle s’effectue et le menu s’affiche à nouveau. Pour sortir d’un select
il faut utiliser un break.
select variable in liste_contenu
do
traitement
done
Si in liste_contenu n'est pas précisé, ce sont les paramètres de position qui sont utilisés et
affichés.
Exemple :
$ cat >select.ksh
# !/bin/ksh
PS3="Votre choix :"
"Quelle donnee ?"
select reponse in Moussa Rose Fifi quitte
do
if [[ "$reponse" = "quitte" ]]
then
break
fi
echo "Vous avez choisi $reponse"
done
echo "Au revoir."
exit 0
$ ./select.ksh
./select.ksh: !#/usr/bin/ksh: not found
Quelle donnee ?
1) Moussa
2) Rose
3) Fifi
4) quitte
Votre choix :1
Vous avez choisi Moussa
Votre choix :3
Vous avez choisi Fifi
Votre choix :4
Au revoir.
11. read et |&
Le Bourne shell ne proposait pas de mécanisme simple pour lire par exemple un fichier
ligne à ligne. Le Korn Shell permet d’envoyer le résultat d'une commande dans un tube
avec la syntaxe « |& » et de récupérer ce résultat avec la commande read -p.
commande |&
read -p variable
Exemple : soit le fichier nommé liste
$ cat >liste
Produit objet prix quantites
souris optique 30 15
dur 30giga 100 30
dur 70giga 150 30
disque zip 12 30
disque souple 10 30
ecran 15 150 20
ecran 17 300 20
ecran 19 500 20
52
GANDHI
Programmation Shell
clavier 105 45 30
clavier 115 55 30
carte son 45 30
carte video 145 30
Écrivons un script ksh qui permet de lire le fichier liste ligne par ligne
$ cat > read.ksh
#!/bin/ksh
typeset -i compteur
compteur=1
cat liste |&
while read -p ligne
do
echo "$compteur\t $ligne"
compteur=compteur+1
done
$ ./read.ksh
1 Produit objet prix quantites
2 souris boutons 30 15
3 dur 30giga 100 30
4 dur 70giga 150 30
5 disque zip 12 30
6 disque souple 10 30
7 ecran 15 150 20
8 ecran 17 300 20
9 ecran 19 500 20
10 ecran 21 500 20
11 clavier 105 45 30
12 clavier 115 55 30
V. COMPLEMENT :
1. La Crontab
Le mécanisme cron permet l’exécution régulière et automatique de commandes. A chaque
démarrage de la machine (en fait suivant le niveau d'init) un service (daemon) est lancé,
généralement appelé cron ou crontab (/usr/sbin/cron, /etc/cron, /sbin/cron, ...) qui lit une
table spécifique appelée crontab.
La crontab est généralement placée dans /var/adm/cron ou /etc/cron ou /usr/lib/cron. Tous
les utilisateurs n’ont pas forcément le droit d’utiliser la crontab (cron.allow et cron.deny).
La commande crontab permet d’accéder et de modifier les données de la table.
Pour lister une crontab, on utilise l’option « -l ». L’option « -r » permet de supprimer tous
les ordres de sa crontab. Pour éditer sa crontab personnelle, on utilise l’option « -e ». Un
éditeur vi est lancé.
A la sauvegarde, le contenu qui aura été saisi sera le contenu de la crontab de l'utilisateur.
Syntaxe de cron :
Les commandes que le démon “cron” doit exécuter s’écrivent sur une seule ligne et
doivent obligatoirement respecter la syntaxe suivante
mm hh jj MM JJ commande option
- mm : minutes, de 0 à 59
- hh : heures, de 0 à 23
- jj : jour du mois, de 1 à 31
- MM : mois, de 1 à 12
- JJ : jour de la semaine, 0 à 6 0= dimanche, 1= lundi, ...
mm, hh, jj, MM et JJ peuvent également être substitués par :
52
GANDHI
Programmation Shell
, : La virgule représente le "et". Pour lancer une action le 12 et le 15 du mois, tapez
"12,15" à la place de jj.
- : Le tiré signifie "jusqu’à". Ainsi, "12-15" signifie du 12 au 15.
* : L’étoile représente toutes les valeurs d’un paramètre. Si vous mettez une étoile à la
place de hh, l’action sera effectuée toutes les heures.
/ : Le slash vous permet de spécifier une répétition : pour tous les 3 mois, remplacez MM
par */3.
2. Messages aux utilisateurs
La commande write permet d’envoyer un message à un utilisateur. Par défaut l’utilisateur
doit être connecté sur la même machine (sur un autre terminal). On peut aussi tenter
d'écrire à un utilisateur sur une autre machine. La syntaxe est :
write user terminal [ligne]
write user@machine [ligne]
write -n machine user [ligne]
La commande write est interactive, une fois la connexion établie les utilisateurs peuvent
communiquer en direct. Pour quitter la saisie : Ctrl+D.
La commande wall permet d’envoyer une information à tous les utilisateurs connectés.
L’utilisateur qui ne souhaite pas voir les messages, ou l'administrateur qui veut en
empêcher l' utilisation abusive, peut utiliser la commande mesg.
mesg y (autorisation)
3. ftp
Bien que n’étant pas une commande propre à Unix, il est utile de connaître la commande
ftp (file transfert protocol). Elle permet le transfert de fichiers entre deux machines. Elle
prend comme paramètre le nom de la machine distante. Pour que la commande ftp
fonctionne, il faut que le service ftp fonctionne sur la machine distante et sur le port 21.
Voici un exemple (peu pratique) de connexion avec erreur et nouvel essai.
ftp> open
(to) machine
Connected to machine.
220 machine FTP server (Digital UNIX Version 5.60) ready.
Name (machine:root): root
331 Password required for root.
Password:
530 Login incorrect.
Login failed.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> user
(username) root
331 Password required for root.
Password:
230 User root logged in.
ftp> pwd
257 "/" is current directory.
Le plus simple est tout de même :
$ ftp machine
Connected to machine.
220 machine FTP server (Digital UNIX Version 5.60) ready.
Name (machine:root): root
331 Password required for root.
52
GANDHI
Programmation Shell
Password:
230 User root logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
Voici une liste de commandes ftp.
52
GANDHI
Programmation Shell
VI - EXERCICES :
Soit le fichier nommé liste contenant la liste des noms prénoms d'utilisateurs pour les
quels on doit créer des comptes informatiques sur un système Unix.
Le format de la liste est :
# commentaire
nom1 prénom1
nom2 prénom2
# commentaire
nom3 prénom3
...
1. Écrire un script-shell nommé exo1 qui lit le fichier liste ligne par ligne, et qui en fait
l'écho à l'écran sous la forme :
<nom> <prénom>
Cat >exo1.sh
#!/bin/sh
cat liste | while read w1 w2
do
echo "<$w1> <$w2>"
done
2. Modifier le script avec le nom exo2 pour éliminer la(les) ligne(s) de
commentaires éventuellement présente(s) dans liste (ligne commençant par un caractère
'#' en début de ligne).
Cat >exo2.sh
#!/bin/sh
cat liste | while read w1 w2
do
pre_caract=’echo $w1 | cut c1’
if [ "$ pre_caract " != "#" ]; then
echo "<$w1> <$w2>"
fi
done
3. Modifier le script pour remplacer les caractères accentués par leur équivalent non
accentué : [éèàùç] [eeauc]
cat >exo3.sh
#!/bin/sh
cat liste | while read w1 w2
do
pre_caract=’echo $w1 | cut c1`
if [ "$ pre_caract " != "#" ]; then
w1=`echo $w1 | tr [éèàùç] [eeauc]`
w2=`echo $w2 | tr [éèàùç] [eeauc]`
echo "<$w1> <$w2>"
fi
done
4. Faire afficher à l'écran les informations :
<nom> <prénom> <INITIALES>
en tenant compte des points exo1. et exo2.
Cat >exo4.sh
#!/bin/sh
cat liste | while read w1 w2
52
GANDHI
Programmation Shell
do
pre_caract =`echo $w1|cut c1`
if [ "$ pre_caract " != "#" ]; then
w1=`echo $w1 | tr [éèàùç] [eeauc]`
w2=`echo $w2 | tr [éèàùç] [eeauc]`
ini1=`echo $w1 | cut c1 | tr [az] [AZ]`
ini2=`echo $w2 | cut c1 | tr [az] [AZ]`
ini=$ini1$ini2
echo "<$w1> <$w2> <$ini>"
fi
done
5. Modifier le script pour passer le nom du fichier liste en argument, et contrôler
l'existence du fichier avant de poursuivre le traitement du script.
Utiliser un message de type :
- « Usage : ... », si l'argument n'a pas été donné,
- « Fichier <...> inexistant », si le fichier passé en argument n'existe pas.
#!/bin/sh
fic=$1
if [ "$fic" == "" ]; then
echo "Usage : compte.sh file"
exit
fi
if [ ! f "$fic" ]; then
echo "Fichier <$fic> inexistant!"
exit
fi
cat $fic|while read w1 w2
do
pre_caract =`echo $w1|cut c1`
if [ "$pre_caract" != "#" ]; then
w1=`echo $w1 | tr [éèàùç] [eeauc]`
w2=`echo $w2 | tr [éèàùç] [eeauc]`
ini1=`echo $w1 | cut c1 | tr [az] [AZ]`
ini2=`echo $w2 | cut c1 | tr [az] [AZ]`
ini=$ini1$ini2
echo "<$w1> <$w2> <$ini>"
fi
done
6. Pour éviter les doublons éventuels au niveau des logins, on prend les 2 premiers
caractères du nom et les 2 premiers caractères du prénom, tout en minuscule, pour former
le nom de login de l'utilisateur. Faire afficher ce login à la place de
<INITIALES> de l’exo4.
#!/bin/sh
fic=$1
if [ "$fic" == "" ]; then
echo "Usage : compte.sh file"
exit
fi
if [ ! f "$fic" ]; then
echo "Fichier <$fic> inexistant!"
exit
fi
cat $fic|while read w1 w2
52
GANDHI
Programmation Shell
do
pre_caract =`echo $w1|cut c1`
if [ "$pre_caract" != "#" ]; then
w1=`echo $w1 | tr [éèàùç] [eeauc]`
w2=`echo $w2 | tr [éèàùç] [eeauc]`
ini1=`echo $w1 | cut c1,2 | tr [AZ] [az]`
ini2=`echo $w2 | cut c1,2 | tr [AZ] [az]`
ini=$ini1$ini2
echo "<$w1> <$w2> <$ini>"
fi
done
7. Utiliser le login constitué au point 6. pour créer des comptes en utilisant les
informations suivantes pour la commande useradd :
login : comme défini au point 6.
home : /home/NOM_xy, avec xy : les 2 premières initiales du prénom en minuscule
UID : 1000 pour le premier compte, puis incrémenter de 1 à chaque compte
groupe : users (le créer si besoin)
commentaire : « prénom NOM -TP PROG SHELL»
shell : /bin/bash
passwd : créer un compte « guest » (useradd guest) ;
Lui affecter un mot de passe ; utiliser le mot de passe crypté de test comme mot de
passe pour l'option -p de la commande useradd.
Créer si besoin les répertoires des utilisateurs, changer de propriétaire et de groupe si
besoin.
On créé d'abord un compte test et on lui affecte un mot de passe:
useradd test
passwd test
Changing password for user test.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
#!/bin/sh
fic=$1
if [ "$fic" == "" ]; then
echo "Usage : compte.sh file"
exit
fi
if [ ! f "$fic" ]; then
echo "Fichier <$fic> inexistant!"
exit
fi
DEL=0
if [ "$2" = del ]; then
DEL=1
fi
let uid=1000
cat $fic | while read w1 w2
do
pre_caract=`echo $w1 | cut c1`
if [ "$ pre_caract" != "#" ]; then
w1=`echo $w1 | tr [éèàùç] [eeauc]`
w2=`echo $w2 | tr [éèàùç] [eeauc]`
52
GANDHI
Programmation Shell
ini1=`echo $w1 | cut c1,2 | tr [AZ] [az]`
ini2=`echo $w2 | cut c1,2 | tr [AZ] [az]`
ini=$ini1$ini2
echo "<$w1> <$w2> <$ini>"
echo n "creation du compte $ini : "
pass=`grep test /etc/shadow | cut d: f 2`
useradd c "$w3 $w1TP PROG SHELL" d /home/${w1}_$ini2 g users u $uid s /bin/bash p "$pass" $ini
mkdir /home/${w1}_$ini2
chown R $ini /home/${w1}_$ini2
chgrp R users /home/${w1}_$ini2
fi
let uid=$uid+1
fi
done
8. Tester manuellement la connexion sur les comptes ainsi créés. On change de console
(ALT+F2) par exemple ou lancer une nouvelle console, et on se connecte avec le login à
tester.
9. Modifier le script pour prévoir une option del : cette option détruit les comptes des
utilisateurs (userdel) et affiche à chaque fois un message :
suppression du compte <....> : [OK]
[ERROR] + message
[OK] : si la suppression a réussi
[ERROR] : dans le cas contraire, suivi du message d'erreur de userdel
fichier compte.sh
#!/bin/sh
fic=$1
if [ "$fic" == "" ]; then
echo "Usage : compte.sh file"
exit
fi
if [ ! f "$fic" ]; then
echo "Fichier <$fic> inexistant!"
exit
fi
DEL=0
if [ "$2" = del ]; then
DEL=1
fi
let uid=1000
cat $fic|while read w1 w2
do
pre_caract =`echo $w1 | cut c1`
if [ "$ pre_caract " != "#" ]; then
w1=`echo $w1 | tr [éèàùç] [eeauc]`
w2=`echo $w2 | tr [éèàùç] [eeauc]`
ini1=`echo $w1 | cut c1,2 | tr [AZ] [az]`
ini2=`echo $w2 | cut c1,2 | tr [AZ] [az]`
ini=$ini1$ini2
echo "<$w1> <$w2> <$ini>"
if [ "$DEL" = 1 ];then
echo n "suppression du compte $ini : "
mess=`userdel $ini 2>&1`
if [ $? = 0 ];then
echo [OK]
52
GANDHI
Programmation Shell
else
echo [ERROR] $mess
fi
else
echo n "creation du compte $ini : "
pass=`grep test /etc/shadow | cut d: f 2`
useradd c "$w3 $w1TP ADMIN UNIX" d /home/${w1}_$ini2 g users u $uid s /bin/bash p "$pass" $ini
mkdir /home/${w1}_$ini2
chown R $ini /home/${w1}_$ini2
chgrp R users /home/${w1}_$ini2
fi
let uid=$uid+1
fi
done
MISE EN PLACE D'UN FIREWALL
9. écrire un script permettant de mettre en place un firewall pour contrer les attaques ou
requêtes non autorisées sur notre serveur.
Nous allons utiliser iptables pour créer les règles de notre firewall sous debian.
Attention à bien suivre les instructions, vous pourriez bloquer tout votre serveur
1) Créez un fichier firewall.sh
Première chose à faire, par défaut nous bloquons tout le trafic sortant et entrant.
Ajoutez ces lignes dans votre fichier:
#!/bin/bash
echo Les règles de configurqtion du firewall...
#
#
Pour contrer les relais SMTP et autres requêtes sur votre serveur mail, ajoutez les lignes
suivantes:
#Creation d'une chaine
iptables -N LOG_REJECT_SMTP
52
GANDHI
Programmation Shell
Pour le moment tout est bloqué sauf le SSH, nous allons ajouter des exceptions au
blocage:
# Ne pas casser les connexions etablies
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
echo - Ne pas casser les connexions établies : [OK]
# Autoriser ping
iptables -t filter -A INPUT -p icmp -j ACCEPT
iptables -t filter -A OUTPUT -p icmp -j ACCEPT
echo - Autoriser ping : [OK]
5) Autorisation serveur
et enfin notre serveur mail sur les ports 25 (SMTP), 110 (POP) et 143 (IMAP):
# Mail
iptables -t filter -A INPUT -p tcp --dport 25 -j ACCEPT
iptables -t filter -A INPUT -p tcp --dport 110 -j ACCEPT
iptables -t filter -A INPUT -p tcp --dport 143 -j ACCEPT
52
GANDHI
Programmation Shell
Verification: si tout marche bien, vous devez voir quelque chose de ce genre
Root@serveur:~# iptables -L
Chain INPUT (policy DROP)
target prot opt source destination
LOG_REJECT_SMTP 0 -- adsl-tpe-NET.STATIC.so-net.net.tw/17 anywhere
LOG_REJECT_SMTP 0 -- 122-120-0-0.dynamic.hinet.net/13 anywhere
LOG_REJECT_SMTP 0 -- 168-95-0-0.hinet-ip.hinet.net/16 anywhere
LOG tcp -- anywhere anywhere tcp dpt:6060 recent: CHECK seconds: 60
hit_count: 2 name: SSH side: source LOG level warning
DROP tcp -- anywhere anywhere tcp dpt:6060 recent: UPDATE seconds: 60
hit_count: 2 name: SSH side: source
ACCEPT tcp -- anywhere anywhere tcp dpt:6060 state NEW recent: SET
name: SSH side: source
DROP tcp -- 192.168.0.11 anywhere tcp dpt:ssh recent: UPDATE seconds: 60
hit_count: 4 name: SSH side: source
tcp -- 192.168.0.11 anywhere tcp dpt:ssh recent: SET name: SSH side:
source
ACCEPT tcp -- 192.168.0.11 anywhere tcp dpt:ssh
ACCEPT 0 -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT tcp -- 192.168.0.200 anywhere tcp dpt:snmp
ACCEPT udp -- 192.168.0.200 anywhere udp dpt:snmp
ACCEPT 0 -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere tcp dpt:www
ACCEPT tcp -- anywhere anywhere tcp dpt:https
ACCEPT tcp -- anywhere anywhere tcp dpt:ftp
ACCEPT 0 -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:domain
ACCEPT udp -- anywhere anywhere udp dpt:domain
ACCEPT tcp -- anywhere anywhere tcp dpt:smtp
ACCEPT tcp -- anywhere anywhere tcp dpt:pop3
ACCEPT tcp -- anywhere anywhere tcp dpt:imap2
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy DROP)
target prot opt source destination
ACCEPT 0 -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:ftp
ACCEPT tcp -- anywhere anywhere tcp dpt:www
ACCEPT tcp -- anywhere anywhere tcp dpt:domain
ACCEPT udp -- anywhere anywhere udp dpt:domain
ACCEPT udp -- anywhere anywhere udp dpt:ntp
ACCEPT 0 -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere tcp dpt:smtp
ACCEPT tcp -- anywhere anywhere tcp dpt:pop3
ACCEPT tcp -- anywhere anywhere tcp dpt:imap2
52
GANDHI
Programmation Shell
7) Autorisation du SSH et protection
Maintenant que nous avons vérifié que tout fonctionnait correctement, nous allons pouvoir
ajouter des règles pour le SSH
# Autoriser SSH
//Sur une seule ligne
iptables -t filter -A INPUT -p tcp --dport 6060 -m recent --rcheck --seconds 60
--hitcount 2 --name SSH -j LOG --log-prefix "SSH REJECT"
Changez bien le port 6060 par celui que vous avez finalement choisi.
Dans la règle, nous autorisons le port 6060 pour le SSH, avec deux essais d'identification
possibles. Si les 2 essais échouent, l'IP est bloquée pendant une minute.
Si jamais vous voulez accéder au SSH par le port 22 (par exemple de votre boulot) car le
port 6060 est bloqué, vous pouvez rajouter une règle d'exception:
//Sur une seule ligne
iptables -t filter -A INPUT -p tcp --dport 22 -s VOTRE_IP/32 -m recent --update
--seconds 60 --hitcount 4 --name SSH -j DROP
Attention à ce stade, si vous n'arrivez plus à accéder à votre serveur en SSH, suite à une
mauvaise configuration des règles correspondantes, vous serez obligé de provoquer un
reboot software ou hardware de votre serveur...
Passons maintenant à la mise en place de manière automatique du script:
root@serveur :~# vim /etc/rc.local
Les règles du firewall seront, dès lors activées, dès le démarrage du serveur, donc
vérifier bien avant de n'avoir aucune erreur, sans quoi votre serveur ne serait plus
accessible, même avec un reboot !
SAUVEGARDE DES DONNEES
10. Ecrire un script permettant de faire le backup des répertoires /home,
/var/spool/mail, /etc, /root et /opt vers une partition nommée /backup dans le
repertoire /media comme suit : /media/backup supposé créée depuis l’installation de
Debian sous le format .tar et qui s’exécute le 10, 20 et 30 de chaque mois.
52
GANDHI
Programmation Shell
#!/bin/sh
####################################
#
# Script de montage de fichiers archive.
#
####################################
# Les répertoires à sauvegardés.
fichiers_backup="/home /var/spool /mail /etc /root /opt"
# Où il faut mettre les archives.
dest="/media/backup"
# Création des noms de fichiers archives.
day=$(date +%A) hostname=$
(hostname -s) fichier_archive="$hostname-
$day.tgz" # Affiche le message du
status de demarrage. echo "Backing up
$fichiers_backup to $dest/$fichier_archive" date
echo
# Les fichiers archivés utilise tar.
tar czf $dest/$fichier_archive $fichiers_backup
# Affiche le message du status de la fin.
echo
echo "Backup derminé"
date
# Listé les fichiers sous le format long dans $dest pour vérifier les tailles.
ls -lh $dest
Ainsi pour l’exécuter dans le cron on édite le fichier /etc/crontab puis on place ceci :
0 0 "10,20,30" * * root /root/backup.sh et le script est exécuté le 10, le 20 et le 30 de chaque
mois à 00h :00
Pour voir la liste du contenu de l’archive on fait :
tar –tzvf /media/backup/host-jour.tgz où jour est le jour correspondant au jour de la date concernée
c’est-à-dire si le 4 par exemple est un lundi : tar -tzvf
/mnt/backup/host-Lundi.tgz
et enfin pour restaurer, on fait
tar -xzvf /mnt/backup/host-Lundi.tgz -C /tmp etc/hosts L’option –C permet d’extraire un fichier
vers un cible spécifié. Donc l’exemple précédent, le fichier etc/hosts sera extrait vers /tmp
/etc/hosts
Ainsi pour restauré tous les fichiers dans l’archive on fait :
Cd / puis :
tar -tzvf /mnt/backup/host-Lundi.tgz en mode administrateur et cela réécrira correctement les
fichiers sur le système de fichier.
VII – ANNEXE
bonjour a tous,
52
GANDHI
Programmation Shell
dans le cadre d'un stage, je dois ecrire un script linux (en bash donc) pour permettre a une interface resau
de basculer automatiquement sur une autre interface reseau ( la machine a 2 cartes ) automatiquement...
c'est un script qui sera utilisé par les serveurs donc ils faut que la bascule soit completement transparente
pour les clients.
52
GANDHI