site sans réclame GNU/LinuxDebianÉcrireS'abonner

Le bash, programmation en GNU/Linux

L

es moins jeunes d'entre nous auront connu un temps où l'ordinateur ne connaissait pas l'interface graphique (le bureau, avec ses icônes, ses fenêtres, ses menus...). En ces temps-là, tout se passait au moyen de commandes saisies au clavier en regard d'une invite. Ce mode subsiste avec GNU/Linux ou tout autre Unix, ce qui permet de lancer une application avec des paramètres pointus ou de recevoir des messages (d'erreur) plus explicites.

Mais le bash, c'est aussi la possibilité de créer des scripts complexes.

1. Mode interactif

2. Nomenclature

2.1 Syntaxe
2.2 Opérateurs

3. Variables

3.1 Chaîne et affichage
3.2 Variables numériques
3.3 Tableaux
3.4 Passages de paramètres
3.5 Variables du système

4. Structures

4.1 Tests
4.2 if then else
4.3 Boucle while
4.4 Boucle until
4.5 Boucle for in
4.6 select in
4.7 case esac
4.8 Fonctions

5. Système de fichiers

5.1 Répertoires
5.2 Fichiers
5.3 Affichage

8. Commandes

8.1 Attente
8.2 Extractions
8.3 Mathématique
8.n ...autres en vrac

9. Documentation

1. Mode interactif

Ce mode était utilisé avant le développement de l'interface graphique. Si pour une raison ou une autre, cette dernière ne peut être lancée, vous êtes en mode «ligne de commandes».

Si dans votre interface graphique vous ne trouvez pas de console, souvent représentée par un écran noir parmi les accessoires, frappez [alt-F2] et saisissez xterm, gnome-terminal sous GNOME, mate-terminal sous mate-desktop, ou konsole pour KDE.

nana@olympe:~$

Caractères de contrôle hérités du terminal DEC VT220

[Ctrl-a] se place au début de la ligne sans l'effacer, comme [Ctrl-flèche gauche]
[Ctrl-b] curseur un caractère vers la gauche, comme la flèche gauche
[Ctrl-c] interrompt une commande
[Ctrl-d] mange le caractère suivant, comme [Delete]; ferme le terminal si la ligne de commande est vide
[Ctrl-e] saute à la fin de la ligne, comme [Ctrl-flèche droite]
[Ctrl-f] le curseur va un caractère plus loin
[Ctrl-h] le curseur mange un caractère à gauche, comme [Backspace]
[Ctrl-i] autocomplétion des commandes connues du système, comme [Tab]
[Ctrl-j] saute une ligne plus bas
[Ctrl-k] supprime les caractères à la droite du curseur
[Ctrl-l] saute un écran plus bas, en conservant la ligne de commande
[Ctrl-m] saute une ligne plus bas ([Enter])
[Ctrl-n] descend dans l'historique des commandes, comme [Flèche bas], voir [Ctrl-p]
[Ctrl-o] saute une ligne plus bas
[Ctrl-p] remonte dans l'historique des commandes, comme [Flèche haut], voir [Ctrl-o]
[Ctrl-q] reprend l'action d'une commande interrompue par [Ctrl-s]
[Ctrl-r] recherche dans l'historique des commandes
[Ctrl-s] suspend l'action d'une commande
[Ctrl-t] ramène l'avant dernier caractère après le dernier, le curseur avançant si cela est possible
[Ctrl-u] efface les caractères situés à sa gauche et se place au début
[Ctrl-w] coupe ce qui est à la gauche du curseur
[Ctrl-x][Ctrl-x] revient à une position antérieure du curseur (après s'être déplacé dans la ligne de commande)
[Ctrl-y] copie ce qui a été coupé par [Ctrl-w]
[Ctrl-z] interrompt certaines commandes

2.Nomenclature

Ce qui suit est valable en mode console ou en mode script.

2.1 Syntaxe

# permet d'écrire un commentaire dans le programme. De là le verbe "commenter" (ajouter un #) ou "décommenter" (enlever un #) pour rendre une ligne de script ineffective ou effective.

#! /bin/bash sur la première ligne du script appelle l'application bash pour un lancement automatique. Il faut également que le fichier qui contient le script soit rendu exécutable:

$ chmod 740 nom-du-script

Une expression non réservée est considérée comme une chaîne, jusqu'à l'espace suivant. Pour inclure un ou des espaces dans une chaîne, on utilise l'antislash \ suivi d'un espace, mais les guillemets sont plus indiqués. Voi également sortie de chaînes.

` ` entoure une commande passée au système. a=`ls -l` contient la liste des fichiers du répertoire courant

$ préfixe l'appel à la valeur d'une variable

{ } permettent des remplacements: echo a{pr,rm,r,i}e donne apre arme are aie

; sépare deux ou plusieurs commandes à enchaîner sur une même ligne

* représente un ensemble de caractères qui filtre les fichiers du répertoire courant (A* s'ils commencent par 'A'). \* permet de considérer le caractère * en tant que tel

? représente un caractère dans un filtre de fichiers du répertoire courant (?a* si la deuxième lettre est un 'a'). \? permet de considérer le caractère ? en tant que tel

& permet le lancement d'une commande dans un processus parallèle

&& sépare deux ou plusieurs commandes à enchaîner, mais toute erreur retournée par une commande ne permettra pas le lancement de la suivante.

|| sépare deux ou plusieurs commandes à enchaîner, mais seule l'erreur d'une commande permet le lancement de la suivante.

> fichier dirige le résultat d'une commande vers un fichier, créé pour l'occasion. S'il existe déjà, il est écrasé. C'est une manière très simple de créer un petit fichier texte:

echo "Un homme, une femme" > chabada.txt

Permet également de concaténer plusieurs fichiers:

cat texte1 texte2 > somme.txt

>> fichier ajoute le résultat d'une commande au bout d'un éventuel fichier, ou crée le fichier s'il est inexistant (alors équivalent à > fichier).

| (pipe) enchaîne les commandes où chacune reçoit les résultats de la précédente, permettant un traitement postérieur de la sortie d'une commande.

ls -l | sort listage de fichiers avec une mise en ordre alphabétique
ls -l | grep chaine listage avec un filtre: seuls les fichiers ou répertoires contenant chaine sont affichées

Il est possible d'utiliser more ou less en pipe: ls -l | less

Mots réservés

case ) ) ) esac
for in / do / done
function
if then / elif / else / fi
select in … … … do / done
time
until do / done
while do / done

3. Variables

3.1 Chaîne et affichage

Un nom de variable est définie par une chaîne, dont la valeur ne s'affiche qu'avec le préfixe $:

q=cassis; echo $q # affiche cassis
q=cassis; echo q # affiche q

q est une variable contenant une chaine de six caractères. Si l'on veut inclure des espaces dans la chaîne, il faut utiliser des guillemets ou des échappements:

q="Va donc"; r="She's like a rainbow"

Pour concaténer deux chaînes, ne pas utiliser le signe '+':

a=aze; b=rty; c=$a$b; echo $c

Saisir une chaîne

La commande read permet de saisir une chaîne:

read variable attend une chaîne et [Enter] et la place dans la variable

read nom prenom saisit deux variables, les deux chaînes sont séparées par un espace, attention aux ' et "
-n 5 limite la saisie à 5 caractères, saisie automatique après 5 caractères
-p "Nom: " permet l'affichage d'une chaîne d'invite
-t 30 permet de fixer un nombre de secondes maximal pour la saisie
-s pour cacher la chaîne saisie (mot de passe)

S'il existe plus de chaînes séparées par un espace que de variables réceptrices, c'est la dernière qui ramasse le surplus.

read -n 1 -p "Une touche..."

permet de suspendre un script -n 1 accepte que n'importe quelle touche atteigne le nombre maximal de caractère(s), une variable de réception n'est pas nécessaire

Sortie de chaîne 2016.02

printf et echo -e permettent un affichage sur la sortie standard (a priori la console). Les variables n'affichent leur contenu que si elles sont incluses dans une chaîne entourée de guillemets doubles (sinon, c'est leur $nom qui apparaît).

' ' ne convient pas si

" " par contre

Note: echo -e "'$nom'" affiche le contenu de la variable nom entourée de deux guillemets simples.

Les caractères spéciaux sont interprétés si la chaîne est entourée de guillemets, simples ou doubles:

\a bip (selon la configuration de la console)
\b retour en arrière d'un caractère sans effacer: echo -e "aaa\b\bz" affiche aza
\c interrompt l'affichage de la chaîne (et le retour à la ligne de echo)
\e raccourci pour les séquences ECMA-48 (affichage ligne/colonne et couleurs): printf "\033[..." s'abrège en printf "\e[..."
\f saut de page (en fait \v)
\n saut de ligne avec retour de chariot
\r retour au début de la ligne: echo -e "aaa\rz" affiche zaa
\t saut à la tabulation horizontale suivante (tous les 8 caractères)
\v tabulation verticale: même position une ligne plus bas
\\ affichage de l'antislash
\" permet l'affichage du guillemet double dans une chaîne définie par des guillemets double

Les deux premières séquences suivantes sont valables pour les octets de 32 (\040 ou \x20) à 255 (\377 ou \xFF) dans les tables de 256 caractères iso8859 ou windows-1252 ; les deux suivantes spécifiquement pour un codage unicode:

\nnn caractère exprimé en octal (chiffres de 0 à 7)
\xhh caractère exprimé en hexadécimal (chiffres de 0 à F)
\uhhhh caractère unicode exprimé en 4 chiffres hexadécimaux
\Uhhhh caractère unicode exprimé en 4 chiffres hexadécimaux

La différence entre printf et echo -e est que echo -e ajoute un retour à la ligne en fin de chaîne:

nana@olympe:~$ a=yes ; echo -e "$a\vno!"
yes
   no!
nana@olympe:~$
...mais pas printf :
nana@olympe:~$ a=yes ; printf "$a\vno!"
yes
   no!nana@olympe:~$

L'invite (prompt) nana@olympe:~$ qui suit printf n'est pas affichée à la ligne! Notons que echo -en "" a le même comportement que printf .

% n'est pas interprété de la même façon: il faut le doubler our l'afficher avec printf.

3.2 Variables numériques

L'utilisation de variables numériques nécessite un peu de subtilité.

q=43 est une affectation d'une chaîne de deux chiffres à la variable q. Pour exprimer la valeur de la variable 'q', il faut préfixer cette dernière avec $:

q=43 ; echo $q  # affiche '43', la valeur numérique de 'q'
q=43 ; echo q   # affiche la chaîne 'q'

Le bash n'acceptera un traitement numérique que si l'opération est précédée de let:

q=43; let z=q*2; echo $z  # affiche 86 résultat de 43*2
q=43; z=q*2; echo $z      # affiche la chaîne 'q*2'
q=43; z=$q*2; echo $z     # affiche la chaîne '43*2' ($q ayant exprimé la valeur 43, traitée comme une chaîne)

La division / est une division entière, la mise en exposant est **
% ou mod est l'opération modulo: n % m retourne le reste de la division entière de n par m

+=, -=, *=, /=, %= (mais pas **=) permettent les expressions où le premier opérande reçoit le résultat de l'opération:

q=43; let q+=1; echo $q  #  incrémentation d'une unité: 43+1 = 44

Attention: les expressions ne supportent en général pas les espaces

nana@olympe~$ q= 43
bash: 43 : commande introuvable

3.3 Les tableaux

liste=(1 2 3 4 5 6 7 8 9 10) définit un tableau indexé (une liste de valeurs). On accède à chacune par un entier naturel, la première valeur étant désignée par le rang 0.

${liste[3]} est 4, la première valeur étant représentée par ${liste[0]}.

vlaams=(nul een twee drie vier vijf zes zeven acht negen tien)
read -p "Nombre de 0 à 10: " nummer
echo ${vlaams[nummer]}

Pour assigner une case particulière, on a recours à liste[15]=j, même si cette case n'a pas encore été définie et que les case 11, 12, 13 et 14 ne sont toujours pas définies.

echo ${!tabl[@]} renvoie une chaîne composée de tous les index définis
echo ${tabl[@]} renvoie une chaîne composée de toutes les valeurs du tableau

Les tableaux à deux dimensions en semblent pas possibles, mais il y a moyen de les simuler. Pour un damier de 10x10, soit un tableau à cent valeurs différentes, une coordonnée ne ligne / pe colonne est adressable par ${damier[(n-1)*10+p-1]}. Pour la 5e case de la 3e ligne: (3-1)x10+5-1 est l'index de la valeur dans le tableau.

  0  1  2  3  4  5  6  7  8  9
 10 11 12 13 14 15 16 17 18 19
 20 21 22 23 24 25 26 etc.

Tableaux associatifs

Un tableau associatif est une collection où les valeurs ne sont pas rangées dans une file et accessible par son index, mais par une clé. Deux clés différentes peuvent avoir la même valeur, mais une nouvelle valeur attribuée à une clé remplacera la valeur précédente.

declare -A compter # nécessaire pour qu'un tableau soit associatif
compter=([un]=ek [1]=ek [deux]=do [2]=do [trois]=tin [3]=tin [quatre]=char [4]=char [cinq]=panch [5]=panch)
echo ${compter[trois]} ${compter[4]}

Attention! Sans declare -A nomdutableau, il s'agira d'un tableau indexé, et une chaîne ne sera pas consédérée comme clé mais comme variable et son éventuelle valeur numérique considéré comme index (0 si sa valeur est une chaîne).

echo ${tabl[@]} renvoie une chaîne composée de toutes les valeurs du tableau
echo ${!tabl[@]} renvoie une chaîne composée de toutes les clés d'un tableau associatif

Les tableaux associatifs permettent également de simuler des tableaux multi-dimensionnels:

declare -A multi
multi[3,5]="trois fois cinq"
multi[5,3]="cinq fois trois"
a=3; b=5
echo ${multi[$a,$b]}
echo ${multi[$b,$a]} 

3.4 Passages de paramètres

Lors de l'appel d'un script passé avec des paramètres, les variables $1, $2... récupèrent les valeurs des valeurs passées lors de la saisie du fichier bash,$# le nombre de paramètres passés. Pour le fichier essai.bash:

#! /bin/bash
echo "$# $1 $2 $3"

La saisie de ./essai.bash a b zy 12 retournera la ligne

./essai.bash 4 a b zy

Le nombre de paramètres passé est de 4: a, b, zy et 12, même si seulement 3 variables étaient prévues pour les recevoir.

$@ retournent une chaîne reconstituée de tous les paramètres passés avec la commande, séparés d'un espace: '$1 $2 $3 ...'

$* retournent une chaîne reconstituée de tous les paramètres passés, séparés par le caractère contenu dans la variable système $IFS, en général un espace.

shift permet de décaler les variables *1,*2... d'une variable à droite. C'est intéressant à utiliser dans une boucle jusqu'à épuisement des paramètres:

until [[ -z $1 ]]  # tant que $1 n'est pas une chaîne vide
do
echo $1  # affiche le paramètre
shift    # décale $1 d'un paramètre vers la droite
done

$0 représente la saisie du fichier bash (éventuel chemin plus nom du fichier)
$_ dernière commande exécutée (pas les structures ni echo)
$$ identificateur du processus en cours

$#, $@ et $* varient avec le décalage dû à shift.

3.5 Variables du système

(liste non exhaustive)

$PWD contenant l'adresse absolue du répertoire actuel
$DIRSTACK: le répertoire actuel (sans le chemin)
$OLDPWD contient celle du répertoire précédent.
$HOME contient l'adresse du répertoire de base de l'utilisateur (/home/toto).

$BASH_VERSION '4.2.37(1)-release' version du bash
$MACHTYPE 'x86_64-pc-linux-gnu' architecture
$HOSTTYPE 'x86_64' type de la machine
$OSTYPE: 'linux-gnu'

Le tableau BASH_VERSINFO contient également ces informations:

${BASH_VERSINFO[0]} retourne 4: numéro majeur de la version
${BASH_VERSINFO[1]} retourne 2: numéro mineur de la version
${BASH_VERSINFO[2]} retourne 37: numéro de correction de patch
${BASH_VERSINFO[3]} retourne 1: ?
${BASH_VERSINFO[4]} retourne 'release'
${BASH_VERSINFO[5]} retourne 'x86_64-pc-linux-gnu': architecture

$UID le numéro de l'utilisateur (501, 1000...)
$LOGNAME nom de l'utilisateur
$EUID le numéro de l'utilisateur effectif (501, 1000...), la même chose la plupart du temps
$GROUPS numéro de groupe à qui appartient l'utilisateur ???
$HOSTNAME 'olympe' nom de la machine

$IFS séparateur de champ (nouvelle ligne, tabulation, espace...)
$PATH /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games les adresse des binaires
$PS1 à PS4 les différentes définitions de l'invite
$SECONDS nombre entier de secondes du déroulement du script ou de l'ouverture du terminal
$RANDOM renvoie un entier positif aléatoire < 32768. let "a=$RANDOM%6+1" ($RANDOM modulo 6 renvoie les nombres de 0 à 5 inclus) simule le jet d'un dé. Voir l'exemple dans une fonction.

$COLORTERM nom du terminal, de la console
$LANG la locale installée, par exemple fr_FR.UTF-8 ou fr_BE.UTF-8

4. Structures

Certaines structures contiennent un test.

4.1 Tests

Ces tests sont utilisés dans les structures IF, WHILE et UNTIL.

Tests sur les chaînes

Comme une valeur est a priori une chaîne, nous commencerons par les tests réalisés sur les chaînes.

[ -n $chaine ] vérifie que la chaine n'est pas vide
[ -z $chaine ] vérifie que la chaine est vide ("" ou '')

[ $ch1 = $ch2 ] teste l'égalité entre deux variables chaînes
[ $ch1 == $ch2 ] est un équivalent de l'expression précédente
[ $ch1 != $ch2 ] teste l'inégalité entre deux variables chaînes

[ $ch1 "<" $ch2 ] teste l'antériorité de la première chaîne (ordre alphabétique)
[ $ch1 ">" $ch2 ] teste la postériorité de la seconde chaîne (ordre alphabétique)

Les guillemets sont nécessaires pour éviter la confusion avec les redirections de données. Attention: les lettres accentuées viennent après l'alphabet: a...z, é, ù...

Tests sur les nombres

Rappel: une variable numérique est initialisée avec l'expression let "var=43"

[ $a -eq $b ] (equal) teste l'égalité entre deux nombres (ou variables numériques)
[ $a -ne $b ] (non equal) teste l'inégalité entre deux nombres
[ $a -lt $b ] (lesser than) teste si le premier nombre est plus petit que le second
[ $a -gt $b ] (greater than) teste si le premier nombre est plus petit que le second
[ $a -le $b ] (lesser or equal) teste si le premier nombre est plus petit ou égal au second
[ $a -ge $b ] (greater or equal) teste si le premier nombre est plus grand ou égal au second

Tests sur les fichiers

[ -e $nom ] (exist) vérifie l'existence d'un fichier ou répertoire

[ -d $nom ] (directory) vérifie que le nom est celui d'un répertoire
[ -f $nom ] (file) vérifie que le nom est celui d'un fichier
[ -L $nom ] (Link) vérifie que le nom est celui d'un lien symbolique

[ -r $nom ] (readable) vérifie que le fichier est lisible (r ou 4).
[ -w $nom ] (writable) vérifie que le fichier est modifiable (w ou 2)
[ -x $nom ] (executable) vérifie que le fichier est exécutable (x ou 1)

[ nom1 -nt $nom2 ] (newer than) vérifie que le premier fichier est plus récent que le second
[ nom1 -ot $nom2 ] (older than) vérifie que le premier fichier est plus ancien que le second

Expressions régulières

Une expression régulière est une chaîne contenant une série de règles valables décrivant une série de chaînes. Attention: le test est placé entre [[ ]], la chaîne à tester ou la $variable est à gauche et l'expression régulière est à droite.

L'égalité =~ permet la recherche d'un pattern de chaîne:

[[ $ch =~ id ]] teste si la chaine contient id
[[ $ch =~ ^di ]] teste si di se trouve au ^début de la chaine
[[ $ch =~ rac$ ]] teste si rac est situé à la fin$ de la chaine
[[ $ch =~ [Cc]lou ]] teste si Clou ou clou se trouve dans la chaîne: [Cc] permet le choix entre C et c
[[ $ch =~ d[ar-t]i ]] teste si dai, dri, dsi ou dti se trouve dans la chaîne. [r-t] signifie les lettres entre r et t
[[ $ch =~ d{2} ]] teste si une chaîne de deux d est contenue dans la chaîne
[[ $ch =~ d{2,5} ]] teste si une suite de 2 à 5 d est contenue dans la chaîne
[[ $ch =~ in|du ]] permet le choix entre les chaînes in et du pour tester
[[ $ch =~ di?n ]] la chaîne doit conternir dn ou din; possibilité de i entre d et n
[[ $ch =~ di+n ]] au moins un i entre d et n dans la chaîne: din, diin, diiin...
[[ $ch =~ di*n ]] pas de i, un ou plusieurs i entre d et n: dn, din, diin, diiin...
[[ $ch =~ (ah){3} ]] teste l'existence de ahahah dans la chaîne
[[ $ch =~ \* ]] pour tester un *, l'expression régulière doit échapper son *

L'égalité == permet des tests d'égalité plus classiques utilisant les jokers. ? vaut n'importe quel signe et * une séquence de plusieurs signes:

[[ $ch == d?n ]] teste l'égalité avec une chaîne de trois lettres commençant par d et terminant par n
[[ $ch == d*n ]] teste l'égalité avec une chaîne de longueur indéterminée commençant par d et se terminant par n

4.2 condition «if then else»

Exécute la ou les commande(s) situées entre then et fi si le test condition(s) s'avère exact. Attention! la syntaxe de bash est assez capricieuse: l'espace est nécessaire entre les parenthèses carrées et l'expression de la condition.

if [ condition(s) ]
then
 commande(s)
fi

Des commandes alternatives peuvent être lancées si la condition n'est pas respectée: elles se placent entre else et fi.

if [ condition(s) ]
then
 commande(s)
else
 autres commande(s)
fi

Il est possible d'imbriquer des conditions:

read -p "Deux nombres séparés par un espace: " n1 n2

if [ $n1 -eq $n2 ]
then
  echo "Les deux nombres sont égaux"
else
  if [ $n1 -lt $n2 ]
  then
    echo "$n1 est plus petit que $n2"
  else
    echo "$n1 est plus grand que $n2"
  fi
fi

Les indentations ne sont pas nécessaires, mais permettent de structurer visuellement le script. Il est encore possible d'utiliser elif, qui peut préciser une condition alternative:

read -p "Deux nombres séparés par un espace: " n1 n2
if [ $n1 -lt $n2 ]
then
  echo "$n1 est plus petit que $n2"
elif [ $n1 -gt $n2 ]
then
  echo "$n1 est plus grand que $n2"
else
  echo "Les deux nombres sont égaux"
fi

Il est permis de condenser l'écriture, au risque de perdre la vision de la structure:

read -p "Deux nombres séparés par un espace: " n1 n2
if [ $n1 -lt $n2 ]
  then echo "$n1 est plus petit que $n2"
elif [ $n1 -gt $n2 ]
  then echo "$n1 est plus grand que $n2"
else echo "Les deux nombres sont égaux"
fi

Et même d'en arriver à ceci (ne pas oublier les ; entre les conditions et les then, et avant le fi):

read -p "Deux nombres séparés par un espace: " n1 n2
if [ $n1 -lt $n2 ]; then echo "$n1 est plus petit que $n2"
elif [ $n1 -gt $n2 ]; then echo "$n1 est plus grand que $n2"
else echo "Les deux nombres sont égaux"; fi

Un bon compromis serait de séparer structure/conditions et commandes sur des lignes différentes:

read -p "Deux nombres séparés par un espace: " n1 n2
if [ $n1 -lt $n2 ] ; then
  echo "$n1 est plus petit que $n2"
elif [ $n1 -gt $n2 ] ; then
  echo "$n1 est plus grand que $n2"
else
  echo "Les deux nombres sont égaux"
fi

4.3 Boucle «while»

Il s'agit d'une structure dans laquelle le script reste tant que la condition d'entrée est maintenue.

while [ condition(s) ]
do
 commande(s)
done 

Elle peut servir à fabriquer un compteur. Le script ci-dessous peut s'interpréter de la sorte: «une variable numérique est initialisée à 0 ; tant qu'elle reste inférieure à 10, elle est affichée puis incrémentée d'une unité».

let "i=0"
while [ $i -lt 10 ]
do
  echo "$i"
  ((i++))
done

break permet de quitter la boucle autrement que par la condition d'entrée de boucle.
continue permet de repasser directement en début de boucle.

Ces deux instructions peuvent suivre un test.

4.4 Boucle «until»

Il s'agit d'une structure dans laquelle le script reste jusqu'à ce que la condition d'entrée soit vraie.

until [ condition ]
do
 commande(s)
done 

Cette boucle peut également servir à fabriquer un compteur. Le script ci-dessous peut s'interpréter de la sorte: «une variable numérique est initialisée à 0; jusqu'à ce qu'elle égale 10, elle est affichée puis incrémentée d'une unité; le code s'interrompt alors.

let "i=0"
until [ $i -eq 10 ]
do
  echo "$i"
  ((i++))
done

break permet de quitter la boucle autrement que par la condition d'entrée de boucle.
continue permet de repasser directement en début de boucle.

Ces deux instructions peuvent être liées à un test.

4.5 boucle «for»

Il ne s'agit pas de la boucle du compteur comme en BASIC ou C, mais d'une structure dans laquelle la ou les commande(s) sont exécutées pour chaque élément d'une liste.

for element in element1 element2 element3 element4 element5
do
 commande(s)
done 

S'il n'y a pas de liste d'éléments, la variable parcourt la liste des variables $1, $2... issue des paramètres de l'appel du script.

for var
do
 commande(s)
done 

break permet de quitter la boucle autrement qu'à la fin du parcours de la liste.
continue permet de repasser directement en début de boucle, et donc de passer à la valeur suivante de la liste parcourue.

Ces deux instructions dépendent souvent d'un test.

4.6 boucle «select»

Il s'agit d'une structure qui ressemble à la boucle for et permet un choix sous forme de menu:

PS3="Invite: "
select variable in proposition1 proposition2 proposition3
do
 commande(s)
done

affichera:

1) proposition1
2) proposition2
3) proposition3
Invite: 

L'exemple suivant permet la sortie d'un des mots 'alpha', 'beta', 'gamma' ou 'chabada' en saisissant respectivement 1, 2, 3 ou 4. PS3="" permet de définir l'invite prenant place après l'énoncé des quatres mots. La condition IF/THEN/ELSE/FI se borne ici à écrire le mot ou sortir avec un autre nombre que de 1 à 4 ; une saisie vide réaffiche le menu.

PS3="Choisir un mots par son numéro: "
select mot in alpha beta gamma chabada; do
  if [[ -n $mot ]]; then
    echo $mot
  else
    echo 'Mauvais choix!'
    break
  fi
done

select fichier in $@ permet un choix entre les paramètres du script, et select fichier in * un affichage de tous les fichiers du répertoire courant, contenu dans $PWD.

4.7 case esac

Cette structure permet un choix où les cas sont prédéfinis. La première ligne contient la variable dont on teste l'égalité avec les valeurs à tester, situées avant le signe ) . Les cas sont séparés entre eux par un double ;; . En dernier lieu, *) règle les cas non définis, similaire à else de la structure if then fi.

let "a=$RANDOM%6 + 1"

case $a in
1) msg="un" ;;
2) msg="deux" ;;
3) msg="trois" ;;
*) msg="autre" ;;
esac

echo "$a: $msg"

Toute la séquence aurait pu s'écrire:

let "a=$RANDOM%6 + 1"
case $a in 1) msg="un" ;; 2) msg="deux" ;; 3) msg="trois" ;; *) msg="autre" ;; esac
echo "$a: $msg"

Il est possible de prévoir des expressions régulières:

let "a=$RANDOM%100"

case $a in
[1-7]) msg="'[1-7]' qui signifie de 1 à 7"
 ;;
[89]|1[0-9]) msg="'[89]|1[0-9]' qui signifie de 8 à 9 ou 1 suivi de 0 à 9"
 ;;
2[0-9]) msg="'2[0-9]' qui signifie 2 suivi de 0 à 9"
 ;;
[3-7][0-9]) msg="'[3-7][0-9]' qui signifie de 3 à 7 suivi de 0 à 9"
 ;;
*) msg="'*' qui signifie tout ce qui n'a pas été prévu"
 ;;
esac

echo "Le nombre $a est capté par l'expression régulière $msg"

4.8 fonctions

Il s'agit d'un bout de code séparé, que l'on peut invoquer de n'importe quel autre endroit du script, à condition que la définition de la fonction se trouve avant l'appel.

function nom_de_fonction {
commande(s)
}
nom_de_fonction

Il est possible de les définir autrement:

nom_de_fonction() {
commande(s)
}

Les valeurs suivant le nom de la fonction sont autant de paramètres, récupérés pour la fonction par $1, $2, $3...

function exposant {
  echo $1 $2
  let "c=$1**$2"
}

exposant 3 4
echo $c

Les variables étant globales, une variable définie dans une fonction correspond à celle utilisée ailleurs. Il est possible de définir des variables locales (dont les valeurs n'influencent pas les variables de même nom en dehors de la fonction) avec local variable

function deuxdes {
  # simule le lancer de deux dés ($RANDOM%6 rend de 0 à 5)
  let "des = $RANDOM%6 + $RANDOM%6 + 2"
}

deuxdes
echo $des

La valeur (de 0 à 255, qui sert de code) renvoyée par un éventuel return est récupérée par la variable $? et librement interprété par le script.

5. Système de fichiers

Attention: la plupart des commandes ci-après ne fonctionnent que si vous disposez des droits suffisants sur les fichiers ou répertoires, ce qui courant pour votre répertoire personnel).

5.1 Répertoires

pwd retourne l'adresse complète du répertoire courant.

ls liste les noms des fichiers et sous-répertoires du répertoire courant
ls -l donne les paramètres des fichiers et répertoires listés (les droits, possesseurs, longueurs, dates...) avant leur nom.
ls -R fait également une recherche dans les sous-répertoires, de façon récursive.
ls --help liste les options utilisables pour la commande.
dir est un alias de ls: il s'emploie de la même façon mais sans coloration des fichiers spécifiques.

cd nom-du-repertoire (change directory) permet d'entrer dans un sous-répertoire listé par ls
cd .. permet de remonter dans le répertoire contenant le répertoire courant
cd nom1/nom2 permet d'entrer directement dans le sous-sous-répertoire nom2
cd / va dans le répertoire racine, le plus haut niveau hiérarchique
cd /home/nana/musique/chanson fixe le répertoire courant, d'où que l'on soit (adressage absolu)
cd ~/musique/chanson est synonyme du précédent pour l'utilisatrice nana uniquement, dont le répertoire personnel (~) est /home/nana

mkdir dirladada crée le sous-répertoire dirladada dans le répertoire courant
rmdir dirladada supprime le sous-répertoire dirladada seulement s'il est vide

cp un deux -R copie l'entièreté du répertoire un dans le répertoire deux

mv un deux

5.2 Fichiers

cp yeap goulp copie le fichier yeap dans le sous-répertoire goulp
cp -u yeap goulp copie le fichier que si un fichier du même nom ne se trouve pas encore dans le répertoire-cible; si un tel fichier y existe déjà, il ne sera remplacé que s'il est plus ancien
cp monfichier ss-rep copie le fichier dans le sous-répertoire ss-rep

mv yeap goulp

echo "" > fichier crée un fichier vide dans le répertoire courant
echo "azerty uiop" > zaza crée dans le répertoire courant le fichier zaza, contenant azerty uiop

touch fichier, qui actualise la date et l'heure d'un fichier existant, crée sinon un fichier vide.

rm fichier détruit irrémédiablement un fichier.

Liens

Un lien est un alias, à savoir un autre nom désignant un même fichier. Il ne s'agit pas d'une duplication du fichier: l'édition à travers un lien modifie le contenu du fichier.

Un lien matériel (hard link) est un autre chemin/nom pointant vers le même fichier (sa localisation matérielle, par exemple sur le disque). Chaque chemin/nom (l'original et les suivants) a la même valeur, et les données du fichiers ne seront effacées que que si tous ces chemins/noms (dont l'original) sont effacés.

Un lien symbolique (symbolic link) pointe vers le nom original, le seul pointant vers les données du fichier. L'effacement du nom original du fichier suffit à l'effacer, cassant tous ses liens symboliques.

ln fichier lien crée un second nom du fichier
ln -s fichier lien crée un lien symbolique
readlink lien retrouve un nom du fichier d'après son lien symbolique (pas d'un lien matériel, qui est un nom de fichier comme un autre)

Affichage de fichiers

cat fichier affiche un fichier dans la console. N'est utile que pour les fichiers-textes, où les caractères sont affichables, et n'est pratique que pour les fichiers courts, car on n'en voit que la fin s'il prend plus d'un écran. zcat et bzcat s'appliquent aux fichiers zippés.

tail fichier affiche les dix dernières lignes (ou un autre nombre si -n nombre) d'un fichier texte. tailf fichier fait la même chose, mais ne rend la main au bash que si le fichier est modifié.

more, zmore et bzmore permet le défilement par écran [Espace] ou par ligne [Enter]

less, zless et bzless (éventuellement à installer) permet également de remonter dans le texte avec les touches fléchées et [PgDn]/[PgUp].

Il est possible de trier les lignes d'un fichier avec sort.

Comparer des fichiers

cmp fichier1 fichier2 compare deux fichiers, et retourne l'endroit («octet x, ligne y») du premier octet non identique. zcmp et bzcmp concerne les fichiers zippés

diff fichier1 fichier2 compare deux fichiers ligne à ligne et retourne toutes les différences. C'est d'ailleurs utilisé pour les patches de code-source de programmes à recompiler. zdiff et bzdiff concerne les fichiers zippés

8. Commandes

Beaucoup de commandes en relation avec le bash restent à présenter ; certaines sont traitées dans les pages console et basiques.

8.1 Attente 2016.02

sleep n attend n secondes (par défaut) ou 3m, 2h ou 5d ; les nombres ne doivent pas être entiers: 1.6m ou .7h ; plusieurs arguments s'additionnent

8.2 Extractions 2016.02

grep

grep pattern fichier(s) permet l'extraction de lignes (délimitées par l'octet 10 \n) d'un ou plusieurs fichier(s). Le pattern est interprété comme une expression régulière, dont vous trouverez des éléments d'explication ici ou .

toto@localhost:~$ grep toto /etc/group
cdrom:x:24:toto
audio:x:29:toto,pulse
  ...
video:x:44:toto
toto:x:1000:
scanner:x:115:saned,toto

retourne les groupes auxquels l'utilisateur toto est affilié. Quelques options:

-v sélectionne les lignes où le pattern n'est pas retrouvé
-i précise que la casse est ignorée, dans le pattern comme dans le(s) fichier(s) cible(s)
-f permet de préciser un fichier où plusieurs patterns ont été définis, un par ligne
-F précise que le pattern est une chaîne de caractères fixes (non des expressions régulières)

-E («extended») et -P (Perl) offrent semble-t-il peu de différence en UNIX, ainsi que les commandes egrep (grep -E ...) et fgrep (grep -F ...). Voyez man grep ou info grep pour plus infos et d'options.

zgrep, zegrep, zfgrep, bzgrep, bzegrep, bzfgrep permettent la recherche dans des fichiers compressés .zip et .bz.

grep agit également sur le flux issu d'une autre commande:

ls -l | grep .txt
cat fichier | grep amarcor

awk

awk (paquet gawk ou original-awk) est un éditeur de base de données en fichiers de simple texte, dont les lignes représentent les observations, les données étant séparées par une tabulation.

toto  25  132  Kza  Tati
nana4584KzaAllen
pep27115HbEtaix

Par exemple, pour trouver les fichiers du répertoire courant pesant moins de 400 octets, il faut filtrer la commande ls -l avec la commande awk qui impose une condition (le sixième champ doit être un nombre de moins de 400 octets) et affiche le neuvième champ, qui représente le nom de fichier:

ls -l | awk '$5 < 400 { print $5 "\t" $9 }'

Pour le reste, man akw

8.3 Mathématiques

factor

factor nnn factorise les entiers jusqu'à 2**64-1

bc

bc lance une calculette scientifique en mode console, mais ne semble pas trop facilement utilisable dans un script.

false + true

Il ne s'agit pas de variables, mais de commandes retournant une valeur.

false simule une commande qui s'interrompt, ne permettant pas dans ce cas le lancement de la suivante:

false && echo yes

true simule une commande qui se termine bien et permet la suite de la ligne dans cet exemple:

true && echo yes
yes

8.n Autres commandes

Droits

su, login, logout, chgrp, chmod, chown - voir basiques

Montage

mount, mountpoint, umount, dd, sync, findmnt, fusermount monte les système FUSE - voir basiques

NTFS: ntfs-3g, ntfs-3g.probe, ntfs-3g.secaudit, ntfs-3g.usermap, ntfscat, ntfsck, ntfscluster, ntfscmp, ntfsdump_logfile, ntfsfix, ntfsinfo, ntfsls, ntfsmftalloc, ntfsmove, ntfstruncate, ntfswipe

Archivage et compression

cpio, tar, gzip, bzip2, bzip2recover, gunzip, bunzip2, uncompress, zforce, znew, gzexe, bzexe - voir console

Éditeurs

ed, red, sed, nano, rnano n'agit que sur un fichier inclus dans la ligne de commande

Système

uname -a renvoie toutes sortes de paramètres: Linux olympe 3.9-1-amd64 #1 SMP Debian 3.9.8-1 x86_64 GNU/Linux

date renvoie la date et l'heure, et permet de la définir sous la forme date --set="2016-4-24 10:55 AM" (en mode super-utilisateur).

lsblk (list blocks)renvoie l'organisation des disques

df (disk free) renvoie les statistiques d'utilisation des disques

dmesg renvoie les avis de mise en route de la machine et des connexions du hardware.

lsmod (list module) renvoie la liste et les dépendances des modules

Processus

open, openvt, ps, kill, wait,

Réseau

nc, nc.traditional ping, ping6, ss, netcat, netstat, nisdomainname, ypdomainname, dnsdomainname, domainname, hostname, ip

À classer

busybox, chacl, chvt, dash, dumpkeys, fgconsole, fuser, getfacl, kbd_mode, kmod, lessecho, lessfile, lesskey, lesspipe, loadkeys, lowntfs-3g, mknod, mktemp, mt, mt-gnu, pidof, mrbash, readlink, run-parts, setfacl, setfont, setupcon, sh, sh.distrib, stty, tempfile, ulockmgr_server, unicode_start, usb_printerid, vdir, vmmouse_detect, which

alias, set, test, unalias, unset bg, bind, builtin, command, declare, dirs, disown, enable, eval, exec, exit pour quitter un script exit + nombre permet un statut d'erreur, export, fc, fg, getopts, hash, help, history, jobs, local, popd, pushd, readonly, select, source, suspend, times, trap, type, typeset, ulimit, umask

9. Documentation

www.tldp.org/LDP/abs/html/ - The Linux Documentation Project

fr.openclassrooms.com/informatique/cours/reprenez-le-controle-a-l-aide-de-linux

www.gnu.org/software/bash/manual/bashref.html