Le scripting Shell intermédiaire
Permettra d’utiliser à bon escient les codes erreurs (exit code) et les fonctionnalités accessibles grâce à l’utilisation du ET (&&) et du OU (||). Vous mettrez ensuite en place vos premières fonctions notamment lors d’un exercice vérifiant l’existence d’un fichier, et vous utiliserez les wildcards (aussi appelés méta-caractères) pour rendre vos scripts beaucoup plus puissants !
Le scripting avancé :
Vous donnera les outils pour utiliser du code plus performant, par exemple grâce au case. Vous serez également capable de générer vos propres logs et d’utiliser le langage YAML pour les fichiers de configuration. Enfin vous en verrez d’avantages sur les variables (unset, export, typeset, readonly, etc…) et sur la commande sed.
Un script
- Contient une série de commandes.
- Ces commandes sont exécutées par un interpréteur (le shell pour les scripts que nous allons voir) les unes après les autres.
- Tout ce que vous pouvez taper en ligne de commande peut être inclus dans un script.
Rendre un script exécutable
Il est important de mettre les droits sur le fichier contenant le script de manière à ce que celui-ci devienne exécutable :
chmod a+x script.sh
Exécuter un script
Pour exécuter un script, vous avez le choix de, soit vous trouver dans le répertoire où se situe votre script, soit d’utiliser le chemin absolu.
# Chemin absolu :
/home/jordan/script.sh
# Chemin relatif (si je suis dans le même répertoire que le script):
./script.sh
Le Shebang !
Au début de chaque script bash, il est important de faire figurer le shebang :
#!/bin/bash
# Remarque : Il en existe d'autres
#!/bin/sh
#!/bin/csh
#!/bin/zsh
#!/usr/bin/python
Les variables
- Les variables sont sensibles à la casse et par convention, on les met toujours en majuscules.
- Attention aux nom de variables : les variables ne peuvent contenir que des underscores, majuscules, minuscules et chiffres (avec la condition de ne pas commencer par un chiffre)
- Attention à ne pas mettre d’espace entre la variable, le signe = et les « .
- Pour utiliser les variables et afficher le contenu associé, il faut faire précéder le nom de la variable par un $.
- Lorsque vous souhaitez inclure une variable dans un mot par exemple, vous pouvez utiliser les { }
#!/bin/bash
PRENOM="Robert"
NOM="CHART"
echo "Bonjour $PRENOM ${NOM}, bienvenue !"
./script.sh
Bonjour Robert CHART, bienvenue !
# Remarque : sans les accolades, la virgule après NOM aurait engendré une erreur.
Lorsque vous souhaitez inclure une variable dans un mot par exemple, vous pouvez utiliser les { }
Assigner les sorties de commande à une variable :
- il faut mettre la variable entre parenthèses
- ou utiliser la back cote ( ` : alt+7) à la place de $( )
./script.sh
echo ${MACHINE}! # renvoi debian!
LISTE=`ls -l`
echo $LISTE # renvoi le résultat de la commande ls
Les tests
Lorsque vous tapez une commande, vous pouvez prendre le temps d’analyser la réponse du système et prendre une décision en fonction de cette réponse. Il est tout à fait possible d’effectuer les mêmes étapes avec le scripting Shell grâce aux tests dont la syntaxe est la suivante :
[ voici-la-condition-du-teste-a-verifier ] ( il est important de respecter les espaces après le [ et avant le ] )
./script.sh
[ -e /home/jordan/bonjour ]
- La commande nous retourne la valeur 0 (True) si le fichier existe
- La commande nous retourne la valeur 1 (False) si le fichier n’existe pas
Pour avoir la liste des tests possibles taper : « help test »
Parmi les opérateur principaux nous avons :
• -e : 0 (True) si le fichier existe
• -d : 0 (True) s’il s’agit d’un dossier
• -r : 0 (True) si le fichier est disponible en lecture pour l’utilisateur
• -s : 0 (True) si le fichier existe et n’est pas vide
• -w : 0 (True) si le fichier est disponible en écriture pour l’utilisateur
• -x : 0 (True) si le fichier est disponible en exécution pour l’utilisateur
#!/bin/bash
PRENOM="Robert"
NOM="CHART"
[ -z $PRENOM ]
echo $?
—>./script.sh
—>1
[ -n $PRENOM ]
echo $?
—>./script.sh
—>0
[ $PRENOM = $NOM ]
echo $?
—>./script.sh
—>0
Ne pas oublier de mettre des espaces avant et après le signe =
Le test d’égalité renvoie 0 si les deux chaînes sont identiques et 1 si elles ne le sont pas
Si l’on veut tester la différence on utilise !=
Les tests sur les chiffres
De la même manière on il est possible de comparer deux nombres entre eux.
chiffre1 -eq chiffre2 : 0 si chiffre1 est égal à chiffre2
Pareil avec : -ne, -lt, -le, -gt, -ge
• chiffre1 –eq chiffre2 : 0 si chiffre1 est égal à chiffre2
• chiffre1 –ne chiffre2 : 0 si chiffre1 est différent de chiffre2
• chiffre1 –lt chiffre2 : 0 si chiffre1 est plus petit que chiffre2
• chiffre1 –le chiffre2 : 0 si chiffre1 est plus petit ou égal que
chiffre2
• chiffre1 –gt chiffre2 : 0 si chiffre1 est plus grand que chiffre2
• chiffre1 –ge chiffre2 : 0 si chiffre1 est plus grand ou égal que
chiffre2
Le code retour d’une commande
- En général, la valeur de retour d’une commande lorsqu’elle c’est exécuté correctement est 0.
- Ne pas hésiter à se servir du manuel (commande man) pour prendre connaissance de l’utilisation détaillée d’une commande.
- Le code retour d’une fonction est disponible avec $? (echo $?)
#!/bin/bash
HOTE=$1
NOMBRE_DE_PAQUETS=$2
ping –c $NOMBRE_DE_PAQUETS $HOTE
if [ "$?" –ne "0" ]
then
echo "L'hote $HOTE n'est pas joignable"
else
echo "L'hote $HOTE est joignable"
fi
Créer son propre code retour :
- Il est tout à fait possible de dire à votre script que dans certaines conditions, il quitte avec un code erreur différent de 0.
- En effet, s’il s’est correctement exécuté, il sortira avec un code égal à 0 (ou égal à celui de la dernière commande exécutée), mais vous pouvez lui spécifier un code différent avec la commande :
exit 1
exit 2 - Attention, car dés que la commande exit est utilisée, le script s’arrête.
Les conditions
Les if / elif / else
if [ condition-est-vraie ]
then
command
elif [ condition-est-vraie ]
then
command
else
command
fi
#!/bin/bash
CHIFFRE1='16'
CHIFFRE2='17'
if [ $CHIFFRE1 –lt $CHIFFRE2 ]
then
echo "$CHIFFRE1 est plus petit que $CHIFFRE2"
elif [ $CHIFFRE1 –gt $CHIFFRE2 ]
then
echo "$CHIFFRE1 est plus grand que $CHIFFRE2"
else
echo "$CHIFFRE1 est égal à $CHIFFRE2"
fi
./script.sh
-> 16 est plus petit que 17
Le case (alternative au if)
case "$VARIABLE" in
premier_cas)
Command1
Command2
;;
deuxieme_cas)
Command1
Command2
;;
*)
Command autre
exit 1
;;
esac
case "$VARIABLE" in
premier_cas)
Command1
Command2
;;
deuxieme_cas)
Command1
Command2
;;
*)
Command autre
exit 1
;;
esac
case "$1" in
start|START)
# ou [sS][tT][aA][rR][tT] )
/etc/init.d/apache2 start
;;
stop|STOP)
# ou [sS][tT][oO][pP] )
kill $(cat /var/run/apache2/apache2.pid)
;;
*)
echo "Merci d'indiquer start ou stop"
exit 1
;;
esac
Les boucles
La boucle for
for VARIABLE in OBJET1 OBJET2 OBJET3 OBJETn
Command1
Command2
done
CHIFFRES="10 11 12 13"
COULEURS="rouge vert noir bleu"
for CHIFFRE in $CHIFFRES
echo "Chiffre : $CHIFFRE"
done
for COULEUR in $COULEURS
echo "La couleur est : $COULEUR"
done
./script.sh
La boucle while
while [ condition-est-vrai ]
do
Command1
Command2
done
#!/bin/bash
while [ -z $PRENOM ]
do
read –p "Quel est votre prenom ?" PRENOM
Done
Echo "Votre prenom est $PRENOM"
./script.sh
Quel est votre prenom ?
Quel est votre prenom ?
Quel est votre prenom ? Robert
Votre prenom est Robert
Les paramètres de position
Les paramètres de position stockent le contenu des différents éléments de la ligne de commande utilisée pour lancer le script.
- Il en existe 10 : $0 jusqu’à $9
- Le script lui-même est stocké dans la variable $0
- Le premier paramètre est stocké dans la variable $1
… - Il est possible d’accéder à toutes les variables de position à partir du $1 grâce au caractère « $@«
- Il existe différents caractères intéressants à utiliser concernant les variables de positionnement.
$# : récupère le nombre de paramètres (à partir du $1)
$* : récupère la liste des paramètres - Pour accéder aux valeurs supérieures à 9, on peut utiliser la commande « shift » qui va décaler les valeurs des paramètres
Entrées utilisateurs
- La commande read : elle permet d’accepter les données du STDIN (entrée standard), c’est à dire va permettre à l’utilisateur d’entrer des données.
- Si l’on veut afficher du texte pour préciser à l’utilisateur quel genre de données nous souhaitons qu’il entre, on peut également utiliser l’option « -p ».
echo "Quel est votre prénom ?"
read PRENOM
# Est égal à
read -p "Quel est votre prénom ?" PRENOM
Utilisation du && : opérateur AND (ET) logique
Utilisation du || : opérateur OR (OU) logique
- Le && permet d’exécuter une deuxième commande uniquement lorsque la première a renvoyé un code erreur église à 0 (signifiant qu’elle s’est bien exécutée).
- permet d’exécuter une deuxième commande uniquement lorsque la première a renvoyé un code erreur différent de 0 (signifiant qu‘elle ne s’est pas exécuté de la bonne manière).
remi@vmi000000:~$ sudo ping -c 1 8.8.8.8 && echo "L'HOTE EST JOIGNABLE"
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=59 time=4.68 ms
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 4.675/4.675/4.675/0.000 ms
L'HOTE EST JOIGNABLE
remi@vmi000000:~$ sudo ping -c 1 www.sitebidon.fr || echo "L'HOTE EST INJOIGNABLE"
ping: www.sitebidon.fr: Name or service not known
L'HOTE EST INJOIGNABLE
Les fonctions
Il existe deux manières de coder une fonction :
# déclarer une fonction en utilisant le mot "function"
function ma-fonction() {
Command1
Command2
}
# Déclarer une fonction sans déclarer le mot "function" :
ma-fonction () {
Command1
Command2
}
# Pour appeler la fonction : retaper son nom sans les parenthèses
ma-fonction
Le passage des paramètres à une fonction
- Le passage des paramètres fonctionne de la même manière que les scripts.
- Le premier paramètre est stocké dans le $1, le second dans le $2, etc…
- Attention, le $0 continue à faire référence au nom du script lui même.
#!/bin/bash
function internet() {
ping -c $1 $2
if [ $? -eq 0 ]
then
echo "La connectivité vers internet est établie"
else
echo "Pas de connectivité vers internet"
fi
}
Internet "1" "8.8.8.8"
Notions de variables globales et locales
- les variables globales peuvent tout à fait être utilisées dans les fonctions à condition qu’elles été déclarées avant la fonction
- les variables déclarées dans une fonction ne peuvent être utilisées qu’une fois que la fonction a été exécutée
- Pour déclarer des variables locales (n’existes que dans la fonction) on utilise « local »
#!/bin/bash
VARIABLE="Jordan"
function demonstration() {
echo "La variable $VARIABLE est utilisable"
local VARIABLE_IN_FUNCTION="1"
}
demonstration
# VARIABLE_IN_FUNCTION n'est pas utilisable
Code retour d’une fonction
- si le code retour n’a pas été défini, alors c’est le code retour de la dernière variable exécutée dans la fonction qui sera celui de la fonction par défaut
- Le code retour d’une fonction est comprise entre 0 et 255
- On peut y accéder grâce à la commande $?
#!/bin/bash
function internet_connectivity() {
ping –c 1 8.8.8.8 && return 0
}
internet_connectivity
if [ $? –eq 0 ]
then
echo "Connectivité vers internet"
fi
Exercice d’application 1
Réaliser le script respectant les règles suivantes :
- Script auquel on passe en argument une liste de fichiers.
- Le script va d’abord vérifier que l’utilisateur a bien saisi des arguments au moment de lancer le script. Si ce n’est pas le cas, alors le script sort avec une erreur 2.
- Le script va vérifier si ces fichiers existent ou n’existent pas et nous afficher la réponse à l’écran.
- Les commandes doivent être intégrées à des fonctions. On souhaite deux fonctions distinctes, une pour la vérification du nombre d’arguments et l’autre pour la vérification de l’existence des
fichiers.
#!/bin/bash
# Recuperation des noms des fichiers
FICHIERS=$@
NOMBRE_ARGUMENTS=$#
# Verification que l'utilisateur a bien saisi des arguments
function verification_arguments(){
if [ $NOMBRE_ARGUMENTS -eq 0 ]
then
echo "Attention, vous n'avez pas saisi les noms de fichiers !"
exit 2
fi
}
# On verifie que le fichier passe en argument n'existe pas deja
function verification_fichier_existe(){
for FICHIER in $FICHIERS
do
ls $FICHIER 2> /dev/null
if [ $? -eq 0 ]
then
echo "Le fichier $FICHIER existe"
else
echo "Le fichier $FICHIER n'esiste pas"
fi
done
}
verification_arguments
verification_fichier_existe $FICHIERS
remi@vmi000000:~$ nano exercice1.sh
remi@vmi000000:~$ sudo chmod a+x exercice1.sh
remi@vmi000000:~$ ./exercice1.sh
Attention, vous n avez pas saisi les noms de fichiers !
remi@vmi000000:~$ ./exercice1.sh ess.txt
Le fichier ess.txt n esiste pas
remi@vmi000000:~$ ./exercice1.sh essai.txt
essai.txt
Le fichier essai.txt existe
Les WILDCARDS
- il s’agit d’un caractère ou d’une chaîne de caractères qui vont être utilisés pour prendre un certain nombre de valeurs
- On parle de Globbing wildcards lorsqu’ils vont matcher avec une liste de fichiers ou de répertoires
- Ils peuvent être utilisés avec la plupart des commandes comme le ls ou le rm
[Classes de] Caractères | Observation |
---|---|
* | match avec tous les caractères (ou l’absence de caractères) qu’il n’y en ait qu’un seul ou plusieurs |
? | match avec un seul caractère |
[…] | Les classes de caractères : il est possible de créer des patterns de recherche très spécifiques en utilisant les classes de caractères. Le matching va se faire avec un ou plusieurs des caractères inclus entre les crochets de la classe. Exemple : ls -l t[aio]t[ai] —> tata titi (sur tata titi tutu tuto) |
! | Exclusion d’un certain nombre de caractères Exemple : ls -l t[aiou]t!u —> tata titi tuto Exemple : ls -l t[!au]t[!u] —> titi toto |
[x-y] * | On peut également créer une plage de caractères grâce aux classes Exemples : [1-3]* : match avec tous les fichiers commençant par 1, 2 ou 3 a-c]* : match avec tous les fichiers commandant par a, b ou c |
Classes de caractères prédéfinies | |
[[:alpha:]] | Toutes les lettres de l’alphabet (minuscules et majuscules) |
[[:alnum:]] | Toutes les lettres de l’alphabet (minuscules et majuscules) ainsi que tous les chiffres (0 à 9) |
[[:digit:]] | Tous les chiffres de 0 à 9 |
[[:upper:]] | Toutes les lettres de l’alphabet en majuscule |
[[:lower:]] | Toutes les lettres de l’alphabet en minuscule |
[[:space:]] | Tous les caractères d’espacement (espace, tabulation, nouvelle ligne, etc…) |
Exemples | Dans un dossier on les fichiers : tata, titi, tutu, toto, 1robert, 2robert, rob, robert1, robert2, t1t1 ls -ls [[:digit:]]robert renvoi les fichiers 1robert et 2robert ls -ls robert[[:digit:]] renvoi les fichiers robert1 et robert2 ls -ls t[[:alpha:]]t? renvoi les fichiers tata, titi, toto, tutu ls -ls t[[:alnum:]]t? renvoi les fichiers tata, titi, toto, tutu, t1t1 |
\? | Pour effectuer des recherches sur des fichiers qui comportent un caractère de type wildcard, il faut utiliser le caractère d’échappement anti-/ avant le wildcard Exemple : on ne peut pas créer un fichier t?t? avec la commande touch (car le caractère ? est du type wildcard). Pour le faire, on devra entrer : touch t\?t\? ls -l t?t? renvoi les fichiers tata, titi, toto, tutu, t1t1 ls -l t\?t\? renvoi le fichier t?t? |
Exercice d’application 2
- Faire un script prenant deux arguments :
- Premier argument : nom d’un fichier
- Deuxième argument : peut prendre plusieurs valeurs comme :
- copy (copie le fichier dans le répertoire /tmp/script)
- delete (supprime le fichier)
- read (lire le fichier).
- Il faudra créer une fonction qui vérifiera que le fichier rentré en argument existe bien, et utiliser les case pour les différentes possibilités.
#!/bin/bash
# On verifie que le fichier passe en argument existe
function verification_fichier_existe(){
ls $1 2> /dev/null
case $? in
0)
echo "Le fichier $FICHIER existe bien"
return 0
;;
*)
echo "Le fichier $FICHIER n'esiste pas"
return 1
;;
esac
}
# Verifie si l'utilisateur a bien indique un nom de fichier
if [ -z $1 ] || [ -z $2 ]
then
echo "Attention a preciser un nom de fichier et l'action"
echo "Actions disponibles : copy, delete, ou read"
exit 1
fi
# Execution de la fonction de verification
verification_fichier_existe $1
if [ $? -ne 0 ]
then
exit 2
fi
# Actions a executer
case "$2" in
copy)
mkdir /tmp/script 2> /dev/null
cp $1 /tmp/script
if [ $? -eq 0 ]
then
echo "Le fichier $1 a bien ete copie dans /tmp/script/"
else
echo "Une ereeur a eu lieu au moment de la copie"
exit 3
fi
;;
delete)
rm $1
if [ $? -eq 0 ]
then
echo "Le fichier $1 a bien ete supprime"
else
echo "Une ereeur a eu lieu au moment de la suppression"
exit 4
fi
;;
read)
cat $1
if [ $? -eq 0 ]
then
exit 0
else
echo "Une ereeur a eu lieu au moment de la lecture"
exit 5
fi
;;
esac
remi@vmi00:~$ ./exercice2.sh
Attention a preciser un nom de fichier et l'action
Actions disponibles : copy, delete, ou read
remi@vmi00:~$ ./exercice2.sh tutu read
Le fichier n'esiste pas
remi@vmi00:~$ ./exercice2.sh toto read
toto
Le fichier existe bien
Salut l'artiste
remi@vmi00:~$ ./exercice2.sh tutu copy
Le fichier n'esiste pas
remi@vmi00:~$ ./exercice2.sh toto copy
toto
Le fichier existe bien
Le fichier toto a bien ete copie dans /tmp/script/
remi@vmi00:~$ ls /tmp/script
toto
remi@vmi00:~$ ./exercice2.sh toto delete
toto
Le fichier existe bien
Le fichier toto a bien ete supprime
remi@vmi00:~$ ls toto
ls: cannot access 'toto': No such file or directory
Premières configurations système
Premier contacts
Premier contacts
Comment fonctionne un VPS
Instalation de la commande sudo
remi ALL=(ALL) NOPASSWD:ALL
%sudo ALL=(ALL:ALL) NOPASSWD:ALL
puis on sauvegarde(Ctrl+o)/quit(Ctrl+x)
# On termine en redémarrant le service sudo:
/etc/init.d/sudo restart
apt update, upgrade, dist-upgrade et full-upgrade : quelles sont les différences ? quel terme utiliser en fonction de se que l’on cherche à faire : Lire l’article suivant…
E t en prime un lien vers un article de l’hébergeur Contabo intitulé : « Debian et Ubuntu Upgrade »