Cet example vous apprendra à créer une interaction avec un menu et sous menu ainsi que des fonctions dans un script
et vous montrera comment utiliser read/if avec des choix multiples
Ce script n'est pas qu'un simple exercice théorique : c'est un assistant d'administration système complet. À travers lui, je vais vous montrer comment créer un outil robuste, interactif et maintenable. On va aborder le :
- while
- read
- if
- PID
- annimation de chargement reél
- couleurs
- gestion des erreures
- menu/sous menu interactif
- ectiture de config avec cat EOF
...
En plus de vous apprendre tout ça, il créer un exellent petit script pour administrer un serveur de sites web
Ce tutoriel a pour but de vous montrer comment réaliser un script un peu plus avancé que le tutoriel de base.
Tout d'abord un rappel, ATTENTION à votre écriture, je ne vois jamais personne le dire mais c'est capitale. Vous serez (et vous devriez etre) ammené à partagé vos scripts, comme les autres partagent avec vous. Il est important d'y inclure deux ou trois petites choses, premiere ligne = #!/bin/bash deuxiéme ligne = la Version de votre script. Ensuite sous forme de commentaires, ajouter votre mail afin de pouvoir recevoir des modification de votre script et bien sur des commentaires dans votre code
Commencer par créer un fichier text disons 'monscript.sh' ouvrez un terminal et entrez la commande suivante:
touch tuto.sh && chmod +x tuto.sh && mousepad tuto.sh mousepad ou autre (nano) bien évidement, ca marche aussi avec libreoffice writer mais un editeur léger suffit. Ok doncpremiére ligne #!/bin/bash
la deuxiéme ligne # V=0.01
la troisieme ligne # votre@mail.com.
et les quatriéme et cinquiéme lignes :
# Le nom du script et à quoi sert le script.
Ensuite une ou deux lignes vides pour la clarté,
On commence le script et on declare les variables avant les fonctions pour que les differentes fonctions les reconnaissent:
# Couleurs
NOIR='\e[30m'
ROUGE='\e[31m'
VERT='\e[32m'
JAUNE='\e[33m'
BLEU='\e[34m'
VIOLET='\e[35m'
CYAN='\e[36m'
BLANC='\e[37m'
NOIR_G='\e[1;30m'
ROUGE_G='\e[1;31m'
VERT_G='\e[1;32m'
JAUNE_G='\e[1;33m'
BLEU_G='\e[1;34m'
VIOLET_G='\e[1;35m'
CYAN_G='\e[1;36m'
BLANC_G='\e[1;37m'
NEUTRE='\e[0m'
# Annimations
FRAMES=("( •_• )" "( o_o )" "( 0_0 )" "( 0_o )" "( o_0 )" "( -_- )" "( •_• )" "( -_- )" "( o_0 )" "( 0_o )" "( 0_0 )" "( o_o )")
# Autres variables
ScriptMsg=""
Monscript="Bad-Lab's Assist"
Premiere Fonction, certaines actions necessite d'etre admin, donc on check et ajoute sudo si necessaire :
Fonction_admin() {
# Vérification si root
if [ "$EUID" -eq 0 ]; then
# Déjà root, exécution directe
SUDO_CMD=""
else
# Non root, validation du mot de passe en premier plan
if sudo -v; then
# ajout de la commande sudo pour les futures commandes
SUDO_CMD="sudo"
else
echo "Erreur : authentification sudo échouée."
return 1
fi
fi
}
Puis une fonction pour l'annimation de chargement :
Fonction_annimation() {
# On récupére le PID du processus recue
local pid_a_suivre=$1
# On verifie que le processus est toujours en cours
while kill -0 $pid_a_suivre 2>/dev/null; do
# Si le processus est actif
for frame in "${FRAMES[@]}"; do
if ! kill -0 $pid_a_suivre 2>/dev/null; then break; fi
echo -ne "\r${CYAN_G}[${VERT_G} $frame ${CYAN_G}]${NEUTRE}"
sleep 0.25
done
done
# Une fois le processus términé, on efface la ligne de l'annimation
echo -ne "\r\e[K"
}
On ajoute des fonctions de mise à jour séparées, pour ne pas lancer un upgrade si on veut un simple update :
Fonction_apt_update() {
$SUDO_CMD apt update > /dev/null 2>&1 &
# Récupération du PID
local pid=$!
Fonction_annimation "$pid"
ScriptMsg="Mises à jour des dépots effectuée avec succes"
return $?
}
Fonction_apt_upgrade() {
$SUDO_CMD apt upgrade -y > /dev/null 2>&1 &
# Récupération du PID
local pid=$!
Fonction_annimation "$pid"
ScriptMsg="Mises à jour système effectuée avec succes"
return $?
}
Il va falloir des logiciels, donc on ajoute des fonctions pour installer le serveur web ainsi que le générateur de Certificats SSL :
Fonction_install_serveur_web() {
$SUDO_CMD apt install nginx snapd -y > /dev/null 2>&1 &
# Récupération du PID
local pid=$!
Fonction_annimation "$pid"
ScriptMsg="Serveur Web installé et prét à étre configuré"
return $?
}
Fonction_install_ssl() {
$SUDO_CMD snap install --classic certbot > /dev/null 2>&1 &
# Récupération du PID
local pid=$!
Fonction_annimation "$pid"
$SUDO_CMD ln -s /snap/bin/certbot /usr/bin/certbot
return $?
}
Une fois le serveur web installé, il faut le configurer donc on ajoute une fonction pour ecrire la configuration du Serveur Web :
Fonction_config_server_web() {
Fonction_admin
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> redirigez votre nom de domaine vers l'Ip de votre serveurs dans les paramettres de votre dns"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Vous devrez aussi rediriger les port 80 et 443 de votre box internet vers l'ip locale de votre serveur"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Activez l'ip fixe pour votre box internet(sur le site web de votre fournisseur d'accés) ainsi que l'ip locale fixe de votre serveur(dans les paramettres de votre box internet."
sleep 2
while true; do
## Demande si configuration immediate ou non avec lecture de la réponse utilisateur
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Voulez vous configurer un site web maintenant?(Oui/Non)"
echo -ne "\n${CYAN_G}[${VERT_G}$USER${JAUNE_G}@${VIOLET_G}$Monscript${CYAN}] ${NEUTRE}>> ${NEUTRE}"
## Récupération de la réponse utilisateur avec
read -r User_Msg
if [[ "$User_Msg" =~ ^[oO](ui)?$ ]]; then
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Renseignez le nom de domaine de votre site web sans www"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Quel est le nom de votre site web?(exemple : mon-site.com)"
echo -ne "\n${CYAN_G}[${VERT_G}$USER${JAUNE_G}@${VIOLET_G}$Monscript${CYAN}] ${NEUTRE}>> ${NEUTRE}"
read -r User_Msg
## Création de la configuration
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Configuration du serveur web pour : $User_Msg"
$SUDO_CMD mkdir -p /var/www/"$User_Msg"
$SUDO_CMD bash -c "cat > /etc/nginx/sites-available/$User_Msg.conf <
server_name $User_Msg www.$User_Msg;
root /var/www/$User_Msg;
index index.html;
location / {
try_files \$uri \$uri/ =404;
}
}
EOF"
Votre site web aura besoin de https donc dans la même fonction on lance la configuration du certificat SSL :
$SUDO_CMD rm -f /etc/nginx/sites-enabled/default
$SUDO_CMD ln -sf /etc/nginx/sites-available/$User_Msg.conf /etc/nginx/sites-enabled
$SUDO_CMD chown -R www-data:www-data /var/www/$User_Msg
$SUDO_CMD chmod 755 -R /var/www/$User_Msg
echo -ne "\r\e[K"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Vous allez maintenant devoir configurer le certificat SSL pour : $User_Msg"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Cela vous fera obtenir le petit cadenas ainsi que la connexion httpS"
sleep 1
$SUDO_CMD systemctl reload nginx
$SUDO_CMD certbot --nginx
$SUDO_CMD systemctl reload nginx
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Si ce n'est pas déjà fait :"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Votre serveur est prét, n'oubliez pas de rediriger votre nom de domaine vers l'Ip de votre serveurs dans les paramettres de votre dns"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Vous devrez aussi rediriger les port 80 et 443 de votre box internet vers l'ip locale de votre serveur"
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Activez l'ip fixe pour votre box internet(sur le site web de votre fournisseur d'accés) ainsi que l'ip locale fixe de votre serveur(dans les paramettres de votre box internet."
sleep 2
ScriptMsg="Votre serveur web est actif et dispose d'un certificat ssl pour le site web : $User_Msg"
break
return 0
elif [[ "$User_Msg" =~ ^[nN](on)?$ ]]; then
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> d'accord on fera ça plus tard..."
sleep 1
break
elif [[ -z "$User_Msg" ]]; then
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Répondez par Oui ou Non :"
else
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Réponse non reconnue."
echo -e "${CYAN_G}[${JAUNE_G}.:${VERT_G}$Monscript${JAUNE_G}:.${NEUTRE}${CYAN_G}] >> Répondez par Oui ou Non :"
fi
done
}
On créer le menu principal, on utilise une boucle(while) avec une sortie propre et la variable $ScriptMsg pour communiquer avec l'utilisateur :
On utilise la fonction read pour récupérer ce que l'utilisateur choisi dans le menu
Puis on utilise if/elif/else, pour vérifier si l entrée est valide et si oui lancer la bonne fonction
Fonction_menu() {
ScriptMsg=""
while true; do
clear
echo -e "${CYAN}==================================${NEUTRE}"
echo -e "${CYAN} $Monscript ${NEUTRE}"
echo -e "${CYAN}==================================${NEUTRE}"
echo -e "${VERT}1)${NEUTRE} Mises à jour système"
echo -e "${VERT}2)${NEUTRE} Serveur Web"
echo -e "${ROUGE}q)${NEUTRE} Quitter"
echo -e "${CYAN}==================================${NEUTRE}"
echo ""
if [[ "$ScriptMsg" != "" ]]; then
echo -e "${VERT_G} ( ⌐■_■ ) ${BLEU_G}>> ${NEUTRE}$ScriptMsg"
ScriptMsg=""
echo ""
fi
echo -ne "\n${CYAN_G}[${VERT_G}$USER${JAUNE_G}@${VIOLET_G}$Monscript${CYAN}] ${NEUTRE}>> ${NEUTRE}"
read -r User_Msg
if [[ -z "$User_Msg" ]]; then
ScriptMsg="Vous devez séléctionner une entrée du menu par son nom ou son numéro"
elif [[ "${User_Msg,,}" =~ ^(q|quitter)$ ]]; then
echo -ne "\n${CYAN_G}[${VERT_G}$USER${JAUNE_G}@${VIOLET_G}$Monscript${CYAN}] ${NEUTRE}>> ${NEUTRE}Fermeture du script"
clear
break
elif [[ "${User_Msg,,}" =~ ^(1|maj|misesàjour|misesajour|miseàjour|miseajour|mises à jour|mises a jour|mise à jour|mise a jour)$ ]]; then
Fonction_mise_a_jour
elif [[ "${User_Msg,,}" =~ ^(2|web|serveur web|serveurweb)$ ]]; then
Fonction_webmenu
else
ScriptMsg="Fonction "$User_Msg" non reconnue, vous devez séléctionner une entrée du menu par son nom ou son numéro"
fi
done
}
Comme pour le menu principal, le menu web(sous menu) utilise une boucle(while) avec une sortie propre et la variable $ScriptMsg pour communiquer avec l'utilisateur :
On utilise la fonction read pour récupérer ce que l'utilisateur choisi dans le menu
Puis on utilise if/elif/else, pour vérifier si l entrée est valide et si oui lancer la bonne fonction avant que quitter proprement la boucle(while>break)
Fonction_webmenu() {
ScriptMsg=""
while true; do
clear
echo -e "${CYAN}==================================${NEUTRE}"
echo -e "${CYAN} $Monscript ${NEUTRE}"
echo -e "${CYAN}==================================${NEUTRE}"
echo -e "${VERT}1)${NEUTRE} Installation Serveur Web"
echo -e "${VERT}2)${NEUTRE} Configuration"
echo -e "${ROUGE}r)${NEUTRE} Retour"
echo -e "${CYAN}==================================${NEUTRE}"
echo ""
if [[ "$ScriptMsg" != "" ]]; then
echo -e "${VERT_G} ( ⌐■_■ ) ${BLEU_G}>> ${NEUTRE}$ScriptMsg"
ScriptMsg=""
echo ""
fi
echo -ne "\n${CYAN_G}[${VERT_G}$USER${JAUNE_G}@${VIOLET_G}$Monscript${CYAN}] ${NEUTRE}>> ${NEUTRE}"
read -r User_Msg
if [[ -z "$User_Msg" ]]; then
ScriptMsg="Vous devez séléctionner une entrée du menu par son nom ou son numéro"
elif [[ "${User_Msg,,}" =~ ^(r|retour)$ ]]; then
ScriptMsg="Retour au menu principal"
break
elif [[ "${User_Msg,,}" =~ ^(1|installation serveur web|installationserveurweb|install|installation)$ ]]; then
Fonction_server_web
break
elif [[ "${User_Msg,,}" =~ ^(2|configuration|config)$ ]]; then
Fonction_config_server_web
break
else
ScriptMsg="Fonction "$User_Msg" non reconnue, vous devez séléctionner une entrée du menu par son nom ou son numéro"
fi
done
}
Les Fonction appelées par les menus, qui apellent differentes Fonction et verifient leurs résultats(si erreure ou non)
La fonction de mise à Jour, qui apelle les fonctions qui lui sont utiles et verifie les erreurs avant de poursuivre
Fonction_mise_a_jour() {
Fonction_admin
Fonction_apt_update
# On verifie que le processus lancé s'est terminé sans erreur.
if [[ $? -ne 0 ]]; then
ScriptMsg="Erreur lors de l'update. Abandon."
# On quitte la fonction et on retourne au menu
return 1
fi
# Deuxième étape (seulement si la 1ère a réussi).
Fonction_apt_upgrade
if [[ $? -ne 0 ]]; then
ScriptMsg="Erreur lors de l'upgrade. Abandon."
return 1
fi
# Si reussite des deux fonction alors retour aux menu avec succés.
ScriptMsg="Installation terminée avec succès !"
return 0
}
Identique à la fonction de mise à jour mais pour le serveur web, l'intérêt de séparer les fonction en debut de script
la fonction apelle égalemnt admin et update mais pas upgrade car non necessaire, ça permet de pouvoir ajouter des fonctions
sans tout recoder pour chaque fonction donc meilleur lisibilité/maintenance/ajout
Fonction_server_web() {
Fonction_admin;
Fonction_apt_update;
# On verifie que le processus lancé s'est terminé sans erreur.
if [[ $? -ne 0 ]]; then
ScriptMsg="Erreur lors de l'update. Abandon."
# On quitte la fonction et on retourne au menu
return 1
fi
Fonction_install_serveur_web;
# On verifie que le processus lancé s'est terminé sans erreur.
if [[ $? -ne 0 ]]; then
ScriptMsg="Erreur lors de l'installation du Serveur Web. Abandon."
# On quitte la fonction et on retourne au menu
return 1
fi
Fonction_install_ssl;
# On verifie que le processus lancé s'est terminé sans erreur.
if [[ $? -ne 0 ]]; then
ScriptMsg="Erreur lors de l'installation du générateur de Certificats SSL. Abandon."
# On quitte la fonction et on retourne au menu
return 1
fi
Fonction_config_server_web;
}
Et pour finir, à la fin, le debut du script
une fonction de nettoyage un trap et un exit dés qu on sort du menu principal
Fonction_cleanup() {
echo -e "\n${ROUGE}Interruption détectée. Fermeture propre...${NEUTRE}"
# stopper le processus enfant en cours :
jobs -p | xargs kill 2>/dev/null
exit 0
}
trap Fonction_cleanup SIGINT SIGTERM
Fonction_menu
exit 0














