Instructions test if case for while select
/bin/bash
), comme une commande unique. Un script peut être lancé en ligne de commande, comme dans un autre script.
bash
gère notamment :
vi
de préférence à mc
qui ne traite pas les
accents (mais mc
est bien pratique !)
#!/bin/bash
.bash
, cette ligne est superflue
#!/bin/bash # script bonjour # affiche un salut à l'utilisateur qui l'a lancé # la variable d'environnement $USER contient le nom de login echo ---- Bonjour $USER ----- # l'option -n empêche le passage à la ligne # le ; sert de séparateur des commandes sur la ligne echo -n "Nous sommes le " ; date # recherche de $USER en début de ligne dans le fichier passwd # puis extraction de l'uid au 3ème champ, et affichage echo "Ton numéro d'utilisateur est " $(grep "^$USER" /etc/passwd | cut -d: -f3)
x
(soit exécutable). Lui accorder cette permission pour tous ses utilisateurs avec chmod
:chmod a+x bonjour
./bonjour
, ./ indiquant le chemin, ici le répertoire courant. Ou bien indiquer le chemin absolu à partir de la racine. Ceci dans le cas où le répertoire contenat le script n'est pas listé dans le PATH
PATH
./etc/skel/.bash_profile
, qui est recopié dans chaque répertoire dont le rôle est d'affiner le profil personnel du shell de chaque utilisateur.
>
et attend la suite de l'instruction (pour quitter Ctrl-C).
sh -x ./bonjour
Pour aider à la mise au point d'un script, on peut insérer des lignes temporaires :
echo $var
pour afficher la valeur de la variable exit 1
pour forcer l'arrêt du script à cet endroit
#!/bin/bash # appel du script : ./bonjour nom prenom if [ $# = 2 ] then echo "Bonjour $2 $1 et bonne journée !" else echo "Syntaxe : $0 nom prenom" fi
echo
, affiche son argument texte entre guillemets sur la sortie standard, c-à-d l'écran.echo
provoque un saut de ligne.echo "Bonjour à tous !"
-e
suit echo
echo "Bonjour \nà tous !" echo -e "Bonjour \nà tous !" echo -e "Bonjour \nà toutes \net à tous ! \c"
read
, permet l'affectation directe par lecture de la valeur, saisie sur l'entrée standard au clavier
read var1 var2 ...
attend la saisie au clavier d'une liste de valeurs pour les affecter, après la validation globale, respectivement aux variables var1, var2 ..
echo "Donnez votre prénom et votre nom" read prenom nom echo "Bonjour $prenom $nom"
variable=valeur
valeur
est une chaine avec des espaces ou des caractères
spéciaux, l'entourer de " " ou de ' ' "
ou '
chaine=Bonjour à tous echo $chaine
$
set
readonly
n=123 ; echo "la variable \$n vaut $n" salut="bonjour à tous !" echo "Alors moi je dis : $salut" echo 'Alors moi je dis : $salut' echo "Alors moi je dis : \"$salut\" " readonly salut salut="bonjour à tous, sauf à toto" echo "Alors moi je dis : $salut"
export variable
export
--> Pour obtenir la liste des variables exportées
user="/home/stage" echo $user u1=$user1 echo $u1 --> ce n'est pas le résultat escompté ! u1=${user}1 echo $u1
$HOME, $PATH, $USER, $PS1, $SHELL, $ENV, $PWD ..
toto
)
[toto@pxx toto]$ moi=Toto [toto@pxx toto]$ p="Je m'appelle $moi" [toto@pxx toto]$ echo Aujourd\'hui, quel jour sommes nous ? ; read jour [toto@pxx toto]echo aujourd'hui $jour, $p sous le nom $USER, est connecté à la station $HOSTNAME
Ces variables sont automatiquement affectées lors d'un appel de script suivi d'une liste de paramètres. Leurs valeurs sont récupérables dans $1, $2 ...$9
$? | C'est la valeur de sortie de la dernière commande. Elle vaut 0 si la commande s'est déroulée sans pb. |
$0 | Cette variable contient le nom du script |
$1 à $9 | Les (éventuels) premiers arguments passés à l'appel du script |
$# | Le nombre d'arguments passés au script |
$* | La liste des arguments à partir de $1 |
$$ | le n° PID du processus courant |
$! | le n° PID du processus fils |
ls -l
echo $? ----> 0
ifconfig ttyS1
echo $? ---> 1
$1 , $2 .... $9
appelées paramètres de position.$#
a=1 ; b=2 ; c=3 ; set a b c echo somme10 1 2 3 4 5 6 7 8 9 10 echo $1, $2, $3
a=1 ; b=2 ; c=3 set a b c echo $1, $2, $3 # les valeurs de a, b, c sont récupérées dans $1, $2, $3
if.. then ..else
, en quelque sorte à la place de variables booléennes ... qui n'existent pas.
test expression
[ expression ]
aux espaces autour de expression
test
, de même , retourne 0 si la condition est considérée
comme vraie, une valeur différente de 0 sinon pour signifier qu'elle est fausse.
option | signification quant au fichier |
---|---|
-e | il existe |
-f | c'est un fichier normal |
-d | c'est un répertoire |
-r | -w | -x | il est lisible | modifiable | exécutable |
-s | il n'est pas vide |
[ -s $1 ] vrai (renvoie 0) si le fichier passé en argument n'est pas vide [ $# = 0 ] le nombre d'arguments est 0 [ -w fichier ] le fichier est-il modifiable ? [toto@p00]$ [ -r "/etc/passwd" ] toto peut-il lire le fichier/etc/passwd
? [toto@p00]$ echo $? --> 0 (vrai) [toto@p00]$ [ -r "/etc/shadow" ] toto peut-il lire le fichier/etc/shadow
? [toto@p00]$ echo $? --> 1 (faux) [toto@p00]$ [ -r "/etc/shadow" ] || echo "lecture du fichier interdite"
[ option chaine ]
option | signification |
---|---|
-z | -n | la chaine est vide / n'est pas vide |
= | != | les chaines comparées sont identiques | différentes |
[ -n "toto" ] ; echo $? affiche la valeur renvoyée 0 ch="Bonjour" ; [ "$ch" = "bonjour" ] ; echo $? affiche 1 [ $USER != "root" ] && echo "l'utilisateur n'est pas le \"root\" !"
[ nb1 option nb2 ]
option | signification |
---|---|
-eq | -ne | égal | différent |
-lt | -gt | strict. inf | strict. sup |
-le | -ge | inf ou égal | sup ou égal |
a=15 ; [ "$a" -lt 15 ] ; echo $?
option | valeur |
---|---|
[ expr1 -a expr2 ] | (and) 0 si les 2 expr sont vraies |
[ expr1 -o expr2 ] | (or) 0 si l'une des 2 expr est vraie |
[ ! expr1 ] | négation |
Quel résultat ? envisager 2 cas ... f="/root" ; [ -d "$f" -a -x "$f" ] ; echo $? note=9; [ $note -lt 8 -o $note -ge 10 ] && echo "tu n'est pas convoqué(e) à l'oral"
if suite-de-commandes then # séquence exécutée si suite-de-commandes rend une valeur 0 bloc-instruction1 else # séquence exécutée sinon bloc-instruction2 fiAttention ! si
then
est placé sur la 1ère ligne, séparer avec un ;
if commande; then .....
Exemples
toto
posséde t-il un compte ? On teste la présence d'une ligne commençant par toto dans /etc/passwd
( >/dev/null
pour détourner l'affichage de la ligne trouvée)
if grep "^toto" /etc/passwd > /dev/null then echo "Toto a déjà un compte" fi
note=17 if [ $note -gt 16 ] ---> test vrai, valeur retournée : 0 then echo "Très bien !" fi
$HOME/.bash_profile
if [ -f ~/.bashrc ] then .~/.bashrc fi
Conditionnelles imbriquées
Pour imbriquer plusieurs conditions, on utilise la construction :
if commande1 then bloc-instruction1 elif commande2 then bloc-instruction2 else # si toutes les conditions précédentes sont fausses bloc-instruction3 fi
Exemples
fichier=/home/toto/devoir1.html if [ -f $fichier -a -r $fichier ] then echo "je vais vérifier ton devoir." elif [ ! -e $fichier ] then echo "ton devoir n'existe pas !" else echo "je ne peux pas le lire !" fi
$#
, est-elle nulle ?
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
case valeur in expr1) commandes ;; expr2) commandes ;; ... esac
Exemples
$USER
case $USER in root) echo "Mes respects M le $USER" ;; jean | stage?) echo "Salut à $USER ;; toto) echo "Fais pas le zigo$USER \!" ;; esac
read reponse case $reponse in [yYoO]*) ...... ;; [nN]*) .......;; esac
case $langue in francais) echo Bonjour ;; anglais) echo Hello ;; espagnol) echo Buenos Dias ;; esac
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
smb
(/etc/rc.d/init.d/smb)
# smb attend un paramètre, récupéré dans la variable $1 case "$1" in start) echo -n "Starting SMB services: " deamon smbd -D echo echo -n "Starting NMB services: " deamon nmbd -D ...;; stop) echo -n "Shutting SMB services: " killproc smbd .... esac
for variable [in liste] do commandes (utilisant $variable) done
for
controlée habituelle fonctionnant comme dans les langages de programmation classiques (utiliser pour cela une boucle while avec une variable numérique).do
et done
apparaissent en début de ligne ( ou après un ;)
for nom in jean toto stage1 do echo "$nom, à bientôt" done
# recopier les fichiers perso. detoto
dans/tmp/toto
for fich in /home/toto/* do cp $fich tmp/toto done
$@
, c'est-à-dire en parcourant la liste des paramètres positionnels courants.
# pour construire une liste de fichiers dans $@ cd /home/stagex ; set * ; echo $@ for nom in $@ do echo $nom done
for nom in /home/stage[1-9] do echo "$nom, tout va bien ?" done
while liste-commandes do commandes done |
La répétition se poursuit TANT QUE la dernière commande de la liste est vraie (c-à-dire renvoie un code de retour nul) | Voici 2 exemples à comparer
echo -e "Entrez un nom de fichier" read fich while [ -z "$fich" ] do echo -e "Saisie à recommencer" read fich done while echo -e" Entrez un nom de fichier" read fich [ -z "$fich" ] do echo -e "Saisie à recommencer" done |
until liste-commandes do commandes done |
La répétition se poursuit JUSQU'A CE QUE la dernière commande de la liste devienne vraie |
Exemples à tester
# Pour dire bonjour toutes les secondes (arrêt par CTRL-C) while true ; do echo "Bonjour M. $USER" sleep 1 doneLecture des lignes d'un fichier pour traitement : noter que la redirection de l'entrée de la commande while .. do .. done est placée à la fin
fich=/etc/passwd while read ligne do echo $ligne ....... done < $fich
break
placé dans le corps d'une boucle, provoque une
sortie définitive cette boucle.
continue
permet de sauter les instructions du corps de la boucle (qui suivent continue) et de "continuer" à l'itération suivante.
Pour les boucles for, while et until
, continue
provoque donc la réévaluation immédiate du test de la boucle.
Exemples importants
Boucle de lecture au clavier arrêtée par la saisie de stop
#!/bin/bash # syntaxe : lecture.sh texte="" while true do read ligne if [ $ligne = stop ] then break else texte="$texte \n$ligne" fi done echo -e $texteLecture des lignes d'un fichier
fich="/etc/passwd"
grep "^stage" $fich | while true
do
read ligne
if [ "$ligne" = "" ] ; then break
; fi
echo $ligne
done
function nom-fct { bloc d'instructions } nom-fct() { bloc d'instructions }
/etc/rc.d/init.d/smb
contient la commande deamon smbd -D
, pourtant à l'essai deamon
est une commande inconnue !/etc/rc.d/init.d/functions
y est appelé.
Celui-ci contient la fonction :
daemon() {
.....
$((expresion arithmétique))
avec la substitution de commande $(commande)
echo $((30+2*10/4)) echo $(( (30+2) * (10-7) /4 ))
chaine="Bonjour, comment allez VOUS aujourd'hui ?" echo $chaine | tr 'A-Z' 'a-z'
set
(voir ci-dessous), il est nécessaire que le séparateur de champ sur une ligne soit l'espace, et non pas par exemple :/etc/passwd
cat passwd | tr ":" " " > passwd.txt
# soit une chaine ch qui contient une liste de mots c="prof eleve classe note" # set va lire chaque mot de la liste et l'affecter aux paramètres de position set $c ; echo $1 $2 $3 $4 shift ; echo $1 $2 $3 $4Le langage bash est inadapté aux calculs numériques. Mais si vraiment on veut calculer (sur des entiers) ..
declare -i k ; k=1 ; p=1 while [ $k -le 10 ] do echo "$k! = " $((p=$p * $k)) ; k= $k+1 doneIdée (saugrenue !) : écrire le script somme-entiers.sh pour calculer la somme 1+2+..+n, où la valeur de n est passée en argument
eval
permettra d'exécuter comme une commande !
message="Quelle est la date d'aujourd'hui ? set $message echo $# ---> le nombre de mots est 6 echo $4 ---> affiche la chaine "date" eval $4 ---> interpréte la chaine "date" comme une commande, donc ...
eval
liste="date;who;pwd" ( ' ' ou " " obligatoires sinon le ; est un séparateur de commandes) eval $liste ---> exécute bien les 3 commandes
tr
d'abord
user="login=toto ; mdp=moi ; nom='Monsieur Toto' ; groupe=profs" eval $user echo $login $mdp $nom $groupe useradd -G $groupe $login echo $mdp | (passwd --stdin $login)
requete
qui a été transmise : nom=toto&prenom=jules&prof=on
(var, valeur)
où var
sont les noms donnés aux composants de formulaire et valeur
les chaines saisis ou exprimant une sélection.requete="nom=toto&prenom=jules&prof=on"# le filtre
tr
va remplacer dans la chaine $requete
qu'il reçoit, tous les caractères & par ;
commande=$( echo $requete | tr '&' ';') echo $commande ---> nom=toto;prenom=jules;prof=on eval $commande ---> exécute le ligne de commande, donc effectue les affectations ! echo $prenom $nom [ $prof = "on" ] && echo "$prenom $nom est professeur"