Cette page me permet de retrouver des scripts en bash qui peuvent resservir (car on oublie lorsqu'on ne pratique pas souvent...).
- Site permettant de vérifier et déboguer ses scripts : https://www.shellcheck.net/. Il est aussi possible d'installer shellcheck dans sa distribution pour tester ses scripts avec un commande du type :
shellcheck my_script
- Conseils sur la robustesse des scripts : https://connect.ed-diamond.com/linux-pratique/lp-133/rendre-ses-scripts-bash-plus-fiables
- Conseils pour sécuriser ses scripts : https://blog.stephane-robert.info/docs/admin-serveurs/linux/scripts-shell-securises/
Un script bash est un fichier exécutant un ensemble de commandes de façon automatisée (équivalent des macros).
Pour lancer ce fichier, on tapera dans un terminal une commande du type :
./fichier_script.sh
I- Problème d'espace, de tirets ou de caractères spéciaux dans les noms de fichiers et de répertoire
Voir :
- Fixer le séparateur avec IFS : https://michauko.org/blog/ifs-separateurs-scripts-bash-174/
- Ignorer les tirets avec l'option "--" ou "./" : https://fr.linux-console.net/?p=2297#gsc.tab=0
II- Créer un sous-dossier identique dans tous les dossiers d'un même répertoire :
Sources :
Le script ci-dessous, crée dans le répertoire courant (là où se situe le script), un sous-dossier "FIR_école" dans tous les dossiers du répertoire courant (utile pour le drive Nextcloud par exemple).
#!/bin/bash
# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" dans mkdir permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
for d in `find . -mindepth 1 -maxdepth 1 -type d`; do
mkdir -p -- "$d"/FIR_école;
done
IFS=$OLDIFS
exit 0
III- Créer un sous-dossier identique dans tous les dossiers d'un même répertoire en reprenant le nom du dossier Principal :
Le script ci-dessous, crée dans le répertoire courant (là où se situe le script), un sous-dossier "RASED Nom de l'école" dans tous les dossiers du répertoire courant (utile pour le drive Nextcloud par exemple).
AVERTISSEMENT : Attention à bien placer le script dans le dossier principal et à le lancer à partir de là !
#!/bin/bash
# Ce script permet de créer, dans le répertoire courant, un sous-dossier "RASED Nom de l'école" dans tous les dossiers existants
#source : https://stackoverflow.com/questions/50285538/linux-shell-loop-for-create-file-in-each-folder
# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" dans mkdir permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
for d in `find . -mindepth 1 -maxdepth 1 -type d`; do
nomDossier=${d##*/}; #enlève "./" devant le nom du dossier
cheminDossier="$d"/RASED\ "$nomDossier"; #Nom de dossier du type "RASED Nom école" le caractère \ sert à échapper l'espace
mkdir -p -- "$cheminDossier";
done
IFS=$OLDIFS
exec bash; # évite de fermer le terminal après l'exécution du script dans un terminal (utile pour debugguer)
exit 0
IV- Récupérer des sous-dossiers ayant le même préfixe vers un dossier récapitulatif :
À partir du dossier racine courant, le script va copier les sous-dossiers commençant par un préfixe précis (RASED, AGRÉMENTS, ...) dans un dossier racine récapitulatif. Les commandes "echo" permettent de vérifier le contenu des variables pour le débogage.
#!/bin/bash
# Ce script permet de créer, dans le répertoire courant, un sous-dossier "Z- RASED Récap" qui recueillera tous les sous-dossiers RASED des écoles existants
#source : https://stackoverflow.com/questions/50285538/linux-shell-loop-for-create-file-in-each-folder
# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" dans mkdir permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
prefixe=RASED
echo "$prefixe"
dossierCourant=${PWD}
echo $dossierCourant
for d in `find . -mindepth 1 -maxdepth 1 -type d`; do
echo "$d"
nomDossier=${d##*/}; #sans "./" devant le nom du dossier
echo "$nomDossier"
cheminDossier="$d"/$prefixe\ "$nomDossier" #Nom de dossier du type "RASED Nom école"; avec \ pour échapper l'espace après RASED
echo "$cheminDossier"
if [ -d "$cheminDossier" ]
then
#echo "${d%/*}" #Nom du dossier parent
cheminDestination="${d%/*}"/Z-\ "$prefixe"\ Récap
echo $cheminDestination
cp -r -p -- "$cheminDossier" "$cheminDestination"; #copie récursivement en gardant les dates originales
fi
done
IFS=$OLDIFS
exec bash # évite de fermer le terminal après l'exécution du script (utile pour déboguer)
exit 0
Autre script beaucoup plus complet, qui permet de choisir comment récupérer les fiches : soit dans leur dossier école pour faciliter le tri, soit uniquement les fiches toutes mélangées. Seules les écoles ayant des fiches sont récupérées.
#!/bin/bash
# Ce script permet de créer, dans le répertoire courant, un sous-dossier "Z- RASED Récap" qui recueillera
# tous les sous-dossiers RASED des écoles existants OU seulement les fiches RASED (sans les sous-dossiers)
#source : https://stackoverflow.com/questions/50285538/linux-shell-loop-for-create-file-in-each-folder
# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
prefixe=RASED
#echo "$prefixe"
dossierCourant=${PWD}
#echo $dossierCourant
#dossierParent="${dossierCourant%/*}" #Nom du dossier parent
dossierDestination="$dossierCourant"/Z-\ "$prefixe"\ Récap
rm -rf "$dossierDestination" #efface l'ancien dossier
mkdir "$dossierDestination"
#echo "$dossierDestination"
QuestionOuiNon () {
QUESTION="Voulez récupérer les dossiers des écoles (si NON seules les fiches seront récueillies) ?"
DEFAUT=true
if [ "$DEFAUT" = true ]; then # Valeur par défaut définie en paramètre
OPTIONS="[O/n]"
DEFAUT="o"
else
OPTIONS="[o/N]"
DEFAUT="n"
fi
read -p "$QUESTION $OPTIONS " -n 1 -s -r INPUT # Execute au premier caractère (-n 1)
INPUT=${INPUT:-${DEFAUT}} # Si $INPUT vide => remplace par $DEFAULT
echo ${INPUT}
if [[ "$INPUT" =~ ^[yYoO]$ ]]; then # True si y,Y,O ou o
REPONSE=true
else # Faux pour le reste
REPONSE=false
fi
}
QuestionOuiNon
#echo "$REPONSE"
for d in `find . -mindepth 1 -maxdepth 1 -type d`; do
#echo "$d"
nb_fichiers=0
nomDossier=${d##*/}; #sans "./" devant le nom du dossier
#echo "$nomDossier"
cheminDossier="$d"/"$prefixe"\ "$nomDossier" #Nom de dossier du type "RASED Nom école"; avec \ pour échapper l'espace après RASED
#echo "$cheminDossier"
nb_fichiers=$(ls -A $cheminDossier | wc -l)
if [ "$nb_fichiers" -gt "0" ]; then # Pour ne recopier que les dossiers RASED ayant des fiches
#echo "dossier $cheminDossier contient $nb_fichiers fichier(s)."
if [ "$REPONSE" = true ]; then
if [ -d "$cheminDossier" ]; then
cp -r -p -- "$cheminDossier" "$dossierDestination"; #copie récursivement en gardant les dates originales
fi
else
if [ -d "$cheminDossier" ]; then
cp -r -p -- "$cheminDossier"/* "$dossierDestination";
fi
fi
fi
done
IFS=$OLDIFS
exec bash # évite de fermer le terminal après l'exécution du script (utile pour debugguer)
exit 0
V- Lister les fichiers des sous-dossiers AVEC DATE DE MODIFICATION :
Ce script doit permettre de lister tous les fichiers des sous-répertoires au même intitulé des écoles ainsi que leur date de modification. Ceci pour vérifier/contrôler leur existence par exemple.
À suivre...
VI- Partager avec un compte Utilisateur plusieurs dossiers commençant par le même mot clé :
Ce script doit permettre de partager tous les sous-dossiers de chaque école commençant par un mot clé avec un compte particulier. Est-ce réalisable avec webDAV ?
Piste : https://github.com/tavinus/cloudmanager ?
À faire...
VII- Déplacer des sous-dossiers commençant par le même préfixe dans un sous-dossier ARCHIVES :
Ce script permet de déplacer dans les dossiers de chaque école, tous les sous-dossiers commençant par un mot clé vers un dossier d'archivage.
Dans l'exemple ci-dessous, le script cherche dans TOUS les dossiers dans lequel il se trouve, un sous-dossier commençant par "RASED" et le déplace dans un sous-dossier "Z-Archives_2022-2023"
#!/bin/bash# Ce script permet de déplacer, dans le répertoire courant où il se trouve, dans tous les dossiers, tous les sous-dossiers ommençant par "RASED" dans un autre sous-dossier "Z-Archives_2022-2023".
#source : https://stackoverflow.com/questions/50285538/linux-shell-loop-for-create-file-in-each-folder# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" dans mkdir permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
destination="Z-Archives_2022-2023"
for d in $(find . -mindepth 1 -maxdepth 1 -type d); do
nomDossierSource=${d##*/}; #sans "./" devant le nom du dossier
#echo "$nomDossierSource";
cheminDestination="$d"/"$destination"; #Nom du dossier de destination; utiliser \ pour échapper les espaces
#echo "$cheminDestination";
for d2 in $(find "$nomDossierSource" -mindepth 1 -maxdepth 1 -type d) ; do
nomDossierADeplacer=${d2##*/};
cheminDossierADeplacer="$d"/"$nomDossierADeplacer";
prefixe=RASED;
if [[ "$nomDossierADeplacer" == "$prefixe"* ]];then
mv "$cheminDossierADeplacer" "$cheminDestination";
fi
done
done
IFS=$OLDIFS
exec bash; # évite de fermer le terminal après l'exécution du script (utile pour debugguer)
exit 0
VIII- Renommer un sous-dossier qu'on trouve dans tous les dossiers :
Ce script permet de renommer un sous-dossier "ARCHIVES" qu'on trouve dans tous les dossiers où se trouve le script en "Z-Archives".
#!/bin/bash
# Ce script permet de renommer, dans le répertoire courant, dans le sous-dossier RASED,
# le sous-dossier "ARCHIVES" en "Z-archives"
# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" dans mkdir permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
ancienNom="/ARCHIVES"
nouveauNom="/Z-Archives"
for d in $(find . -mindepth 1 -maxdepth 1 -type d); do
nomDossierSource=${d##*/}; #sans "./" devant le nom du dossier
echo "$nomDossierSource";
cheminDossierARenommer="$d"/"RASED ""$nomDossierSource""$ancienNom";
echo "$cheminDossierARenommer";
cheminDossierNouveauNom="$d"/"RASED ""$nomDossierSource""$nouveauNom";
echo "$cheminDossierNouveauNom";
if [ -d "$cheminDossierARenommer" ];then
#echo "Le dossier $cheminDossierARenommer existe !";
mv "$cheminDossierARenommer" "$cheminDossierNouveauNom"
fi
done
IFS=$OLDIFS
exec bash; # évite de fermer le terminal après l'exécution du script (utile pour debugguer)
exit 0
IX- Pour fusionner plusieurs fichiers .csv entre-eux :
Voir cette page : https://www.baeldung.com/linux/csv-file-merging
awk '(NR == 1) || (FNR > 1)' *.csv > fichier_unique.csv
X- Pour ne travailler que sur des dossiers ne commençant pas par des préfixes précis :
Dans l'exemple ci-dessous, agit dans les dossiers ne commençant pas par les préfixes "0-" et "Z-" :
#!/bin/bash
# Ce script permet de créer, dans le répertoire courant, un sous-dossier "PROJET D'ÉCOLE"" dans tous les dossiers existant
#source : https://stackoverflow.com/questions/50285538/linux-shell-loop-for-create-file-in-each-folder
# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" dans mkdir permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
prefixe="PROJET_ÉCOLE"
#echo "$prefixe"
for d in `find . -mindepth 1 -maxdepth 1 -type d`; do
nomDossier=${d##*/}; #sans "./" devant le nom du dossier
debutNomDossier=${nomDossier:0:2}
if [ $debutNomDossier != "0-" ] && [ $debutNomDossier != "Z-" ] ; then
#echo $debutNomDossier
cheminDossier="$d"/"$prefixe"\ "$nomDossier"; #Nom de dossier du type "Conseils d'école Nom école"; avec \ pour échapper l'espace après RASED
mkdir -p -- "$cheminDossier";
fi
done
IFS=$OLDIFS
exec bash; # évite de fermer le terminal après l'exécution du script (utile pour debugguer)
exit 0
XI- Pour dézipper des fichiers zip avec mots de passe dans des sous-dossiers à partir d'une liste de mots de passe :
Ici un exemple où on place ce script dans un dossier général (celui d'une circonscription par exemple) contenant des sous-dossiers dont le nom correspond à l'UAI d'une école et dans lesquels se trouve un fichier .zip ayant le même nom que le dossier dans lequel il se trouve (n° UAI) et nécessitant un mot de passe pour le décompacter.
Les mots de passe se trouvent dans un fichier codes_ZIP.csv à la racine du dossier général où chaque ligne comprend l'UAI (nom du sous-dossier) et le mot de passe associé.
On obtient dans le dossier général, l'ensemble des fichiers dézippés (dans mon cas un .pdf et .xlsx par école).
#!/bin/bash
# Script conçu par Thierry Munoz, le 10/09/2024
# Ce script permet de balayer les sous-dossiers se trouvant dans le dossier des écoles de la circonscription où se trouve ce script
# Il dézippe ensuite tous les fichiers .zip à l'aide des codes contenus dans le fichier codes_ZIP.csv dans le dossier de la circo
# $IFS permet de gérer les séparateurs comme l'espace dans les noms de dossiers
# l'option "--" dans mkdir permet d'ignorer les tirets comme séparateur
OLDIFS=$IFS
IFS=$'\n'
for d in $(find . -mindepth 1 -maxdepth 1 -type d); do
nomDossierSource=${d##*/}; #sans "./" devant le nom du dossier
texteLigneCode="$(grep "$nomDossierSource" codes_ZIP.csv)"; #recherche un code lié à l'UAI de l'école'
codeZIP=${texteLigneCode:9}; #récupère le code pour dézipper le fichier de l'école en supprimant les 9 premiers caractères "011xxxxx;"
if [ ! -z "$codeZIP" ]; then #teste si un code de dézippage existe dans le fichier codes_ZIP.csv'
echo "code pour ZIP :" $codeZIP;
echo "$nomDossierSource";
cheminZIPEcole="$d"/$nomDossierSource.zip;
echo "$cheminZIPEcole";
unzip -P $codeZIP $cheminZIPEcole;
fi
done
IFS=$OLDIFS
exec bash; # évite de fermer le terminal après l'exécution du script (utile pour debugguer)
exit 0