Scripts

Mise à jour : Debian 11.2 - Bullseye

Un script est un une séquence de commandes bash exécutable à partir d'un fichier texte

Sommaire

1 - Syntaxe

#! /usr/bin/env bash

Exemple de fichier script :

$ cat démo
#! /usr/bin/env bash
# Ceci est une ligne de commentaire
echo "Test ok" # ceci est une ligne de commande

2 - Exécution

2.1 - Lancement avec ouverture d'une nouvelle session bash

Un script peut-être lancé en ouvrant un nouvelle session bash

$ bash démo
test Ok
$ chmod u+x démo
$ ./démo
test Ok
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
# mv démo /usr/local/bin/
$ démo
test OK

2.2 - Lancement dans la session bash en cours

Un script peut-être lancé sans création d'une nouvelle session bash, avec la commande exec au lieu de bash, après avoir rendu le fichier exécutable. Toutefois, à la sortie du script, la session en cours est fermée.

$ bash
$ ps
PID TTY TIME CMD
2658 pts/0 00:00:00 bash
2677 pts/0 00:00:00 bash
2690 pts/0 00:00:00 ps
$ exec ./démo
Test ok
$ ps
PID TTY TIME CMD
2658 pts/0 00:00:00 bash
2691 pts/0 00:00:00 ps

2.3 - Appel de scripts

Il est possible d'appeler un script depuis un script, sous réserve qu'il soit dans le même répertoire que le script appelant. L'inclusion s'effectue au moyen de la commande "source", suivie du chemin vers le script à inclure. La commande "source" peut-être remplacée par un point . , alias de la commande "source".

Dans l'exemple ci-dessous, les scripts script1 et script2 sont appelés à partir du script "principal"

$ cat principal
#! /usr/bin/env bash
source "./script1"
source "./script2"
echo fin du script
$ cat script1
#! /usr/bin/env bash
echo ceci est produit par le script1
$ cat script2
#! /usr/bin/env bash
echo ceci est produit par le script2
$ bash démo
ceci est produit par le script1
ceci est produit par le script2
fin du script

2.4 - Lancement dans le cadre d'un chroot

Un script peut-être lancé simultanément avec l'ouverture d'un chroot, en indiquant le chemin du script PAR RAPPORT au point de montage :

Exemple, lancement du script script_démo, dans le chroot monté en /mnt_chroot :

$ ls -l /mnt_chroot
.....
script_démo
....

# chroot /mnt_chroot ./script_démo

2.5 - Droits et permissions

$ sudo -l
[sudo] Mot de passe de xxxxx :
Entrées par défaut pour xxxxx sur buster :
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

L'utilisateur xxxxxx peut utiliser les commandes suivantes sur buster :
(ALL : ALL) ALL

2.6 - Debuggage

Pour faire afficher les lignes de commande pendant l'exécution,

$ bash -x démo
+ echo Test ok
Test ok
$ cat démo 
#! /usr/bin/env bash
set -x
# Ligne de commentaire
echo Test ok

$ ./démo
+ echo Test ok
Test ok

2.7 - Fin du script - Valeur de sortie

$ ./démo
....
$ echo $?
0
$ cat démo
#! /usr/bin/env bash
exit 65
$ ./démo
$ echo $?
65

3 - Variables

3.1 - Variables d'environnement

Les variables d'environnement sont disponibles dans le script :

$ var1=inconnu
$ export var2=connu
$ cat démo
#! /usr/bin/env bash
echo var1 est ....$var1
echo var2 est ....$var2
echo $HOME
$ ./démo
var1 est ....
var2 est ....connu
/home/nom_utilisateur

3.2 - Variables "internes"

Les variables créées dans un script ne sont pas disponibles dans le shell parent ;

$ cat démo
#! /usr/bin/env bash
variable_interne=test
echo $variable_interne
$ ./démo
test
$ echo $variable_interne

3.3 - Arguments

Les arguments passés au lancement du script sont utilisables dans le script comme paramètres de positionnement. Exemple :

$ cat démo
#! /usr/bin/env bash
echo Paramètre 1 : $1
echo Paramètre 2 : $2
echo Paramètre 3 : $3
echo Liste de paramètres: $@
echo Nombre de paramètres : $#
echo Nom du script : $0

Utilisation :

$ bash démo ceci est un test de paramètres
Paramètre 1 : ceci
Paramètre 2 : est
Paramètre 3 : un
Liste de paramètres: ceci est un test de paramètres
Nombre de paramètres : 6
Nom du script : démo

4 - Options

4.1 - Principe

Les options (lettre ou chiffre précédé d'un tiret -) de la ligne de commande peuvent être analysées avec la fonction getotps:

$ cat demo 
#! /usr/bin/env bash

while getopts "hv" Option; do

echo "Traitement de l'option $Option"
case $Option in

h) echo "Aide du script : blablabla"
;;

v) echo "Mode verbeux activé"
;;

?) echo "Cette option est inconnue"
;;

esac
done
$ ./demo -h
Traitement de l'option h
Aide du script : blablabla

$ ./demo -v
Traitement de l'option v
Mode verbeux activé

$ ./demo -x
./script_demo : option non permise -- x
Traitement de l'option ?
Cette option est inconnue
$ ./demo -vh -x
Traitement de l'option v
Mode verbeux activé
Traitement de l'option h
Aide du script : blablabla
./demo2 : option non permise -- x
Traitement de l'option ?
Cette option est inconnue

4.2 - Arguments des options

....
while getopts "h:v:" Option; do
...
$ cat demo2
#! /usr/bin/env bash

while getopts "h:v:" Option; do
echo "Traitement de l'option $Option"
echo "Argument $OPTARG"

case $Option in

h) echo "Aide du script : blablabla";;

v) echo "Mode verbeux activé";;

?) echo "Cette option est inconnue";;
esac
done
$ ./demo2 -h HELP -v VERBOSE
Traitement de l'option h
Argument HELP
Aide du script : blablabla
Traitement de l'option v
Argument VERBOSE
Mode verbeux activé

4.3 - Options et arguments

Voir https://stackoverflow.com/questions/11742996/is-mixing-getopts-with-positional-parameters-possible#13400237

$ script.sh [options] ARG1 ARG2
$ cat script.sh
#! /usr/bin/env bash

# Traitement des options
while getopts "hu:" Option; do
case "$Option" in
h) echo Option h;;
u) echo Option u avec argument $OPTARG;;
esac
done

# Traitement des arguments positionnels
ARG1=${@:$OPTIND:1}
ARG2=${@:$OPTIND+1:1}

echo "Argument1 =$ARG1 Argument2 $ARG2"
$ ./test.sh -h -u test doc1 doc2
Option h
Option u avec argument test
Argument1 =doc1 Argument2 doc2

5 - Alias

Pour utiliser un alias dans un script,

#!/bin/bash

# 1 - Activation des alias :
shopt -s expand_aliases

# 2 - Création des alias, par exemple :
alias pingg='ping -c 3 google.fr'

6 - Fonctions

6.1 - Fonctions définies dans un script

$ cat demo.sh
#!/usr/bin/env bash

function bonjour {
echo "Bienvenue Monsieur $1"
}

bonjour titi
bonjour toto
$ ./demo.sh
Bienvenue Monsieur titi
Bienvenue Monsieur toto

6.2 - Fonctions définies dans un script séparé

Des fonctions peuvent être définies dans des scripts séparés qui seront lancés dans le script principal

$ cat fonction.sh
#!/usr/bin/env bash

function bonjour {
echo "******** bienvenue Monsieur $1 ******"
}
$ cat demo.sh
#!/usr/bin/env bash

source"./fonction.sh"

bonjour $1
bonjour $2
$ ./demo.sh  titi toto
******** bienvenue Monsieur titi ******
******** bienvenue Monsieur toto ******

Annexe - Exemples

1 - Recherche de caractères spéciaux "orphelins"

Pour faciliter la recherche des erreurs dues à des caractères spéciaux orphelins ou non appairés (tels que parenthèses, crochets, double et simple quote, ..) orphelins, on peut s'aider de la commande suivante qui affiche les numéros des lignes contenant des nombres impairs d'un caractère donné :

$ tr -cd "\"\n" < nom_script | awk 'length%2==1 {print NR, $0}'

Remplacer le double quote \" par le simple quote '\ pour obtenir les lignes contenant un nombre impair de '

$ tr -cd "\(\n" < nom_script | awk 'length%2==1 {print NR, $0}'
$ tr -cd "\)\n" < nom_script | awk 'length%2==1 {print NR, $0}'

Par comparaison des numéros de ligne, on obtient les lignes dans lesquels le nombre de parenthèses diffèrent de 1 (ou 3 ou ...)

Procéder de même pour les crochets.

2 - Redirections & pipes

2.1 - Distinction entre redirection et pipe

$ echo toto > fichier_test

$ sudo cat /dev/sdb1 > fichier_test

$ shasum - >> fichier_sha
$ echo toto | shasum -

$ sudo cat /dev/sdb1 | pv |shasum - |tee fichier_sha

2.2 - Mise en parallèle de processus

Référence : How to fork/pipe stdin in bash script?

$ sudo cat /dev/sdb1 |sudo tee /dev/sdb2 |shasum - 
$ seq 1 100 |tee >(grep 5 >file1) >(grep 6 >file2) >/dev/null
$ sudo dd if=/dev/sdb1 |tee >(sudo dd of=/dev/sdb2 skip=128) >(shasum - >fichier_sha) |wc -c

Attention à ce que plusieurs commandes n'utilisent pas simultanément vers la même sortie (fichier ou console). Les sorties seront enregistrées / affichées au fur et à mesure de leur arrivée et pourront donc être inexploitables.

3 - Formatage de texte

echo -e "Première ligne \nDeuxième ligne
\tTroisième ligne avec tabulation"
$ Red='\033[0;31m'; Green='\033[0;32m'; Nocolor='\033[0m'

$ echo -e "Ceci_sans_couleur ${Red}Ceci en rouge ${Green}Ceci en vert ${Nocolor}Ceci_sans_couleur"

4 - Attente

$ sleep 4.8  # Attend 4,8 secondes
$ read -p "Continuer? "
$ read -p "Continuer?" -t 5  # Attente 5 secondes maximum