Wiki-Tech.io/Scripting/Bash/Bash.html

487 lignes
34 KiB
HTML
Brut Annotations Historique

Ce fichier contient des caractères Unicode ambigus.

Ce fichier contient des caractères Unicode qui peuvent être confondus avec d'autres caractères. Si vous pensez que c'est intentionnel, vous pouvez ignorer cet avertissement. Utilisez le bouton Échappe pour les dévoiler.

<!--
title: Scripting - Bash
description: Les bases de l'automatisation !
published: true
date: 2021-05-24T10:36:51.230Z
tags:
editor: ckeditor
dateCreated: 2021-05-24T10:36:49.765Z
-->
<figure class="image image_resized" style="width:30.5%;"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Gnu-bash-logo.svg/1200px-Gnu-bash-logo.svg.png" alt="Fichier:Gnu-bash-logo.svg — Wikipédia"></figure>
<h1 style="text-align:justify;">Shell</h1>
<p style="text-align:justify;">Sous Linux, un shell est l’interpréteur de commandes qui fait office d’interface entre l'utilisateur et le système d’exploitation. Il s’agit d’interpréteurs, cela implique que chaque commande saisie par l’utilisateur et vérifiée puis exécutée. Nous avons déjà parlé des différents types de shell existants (csh, tcsh, sh, bash, ksh, dash, etc.). Nous travaillerons plus avec le bash (Bourne Again SHell).</p>
<p style="text-align:justify;"><br>Pour rappel, un shell possède deux principaux aspects :</p>
<ul>
<li style="text-align:justify;">Un aspect environnement de travail</li>
<li style="text-align:justify;">Un aspect langage de programmation</li>
</ul>
<h1 style="text-align:justify;">L’environnement</h1>
<p style="text-align:justify;">L’environnement de travail d’un Shell doit être agréable et puissant (rappel CLI GUI), bash permet entre autres choses de :</p>
<ul>
<li style="text-align:justify;">Rappeler des commandes précédentes (historique)</li>
<li style="text-align:justify;">Modifier en ligne du texte de la commande courante (bi, emacs, nano)</li>
<li style="text-align:justify;">Gestion des travaux lancés en arrières-plan (jobs)</li>
<li style="text-align:justify;">Initialisation adéquate des variables de configuration (chaîne d’appel de l’interpréteur, chemins de recherche par défaut)</li>
</ul>
<p style="text-align:justify;">Pour illustrer ça, voyons que le Shell permet d’exécuter une commande en mode interactif ou bien par l’intermédiaire de fichiers de commandes (scripts). En mode interactif, bash affiche à l’écran une chaîne d’appel (appelée prompt ou invite) qui se termine par défaut par le caractère # pour l’administrateur (root), et par le caractère $ pour les autres utilisateurs. Sous Windows le prompt est souvent le nom du chemin où l’on se trouve, suivis de &gt; , par exemple : “<strong>C:\Windows\System32&gt;</strong></p>
<h1 style="text-align:justify;">Un langage de programmation</h1>
<p style="text-align:justify;">Les shells ne sont pas uniquement des interpréteurs de commandes mais de véritables langages de programmation, un shell comme le bash intègre :</p>
<ul>
<li style="text-align:justify;">les notions de variables</li>
<li style="text-align:justify;">les opérateurs arithmétiques</li>
<li style="text-align:justify;">les structures de contrôle</li>
<li style="text-align:justify;">les fonctions</li>
<li style="text-align:justify;">etc.</li>
</ul>
<p style="text-align:justify;">Par exemple :</p>
<pre><code class="language-plaintext">$ mavariable=5 #=&gt; affectation de la valeur 5 dans la variable qui a pour nom “mavariable”
$ echo $((mavariable +3)) #=&gt; affiche la valeur de l’expression mavariable
8</code></pre>
<h2 style="text-align:justify;">Avantages et inconvénients des shells</h2>
<p style="text-align:justify;">L’étude d’un shell comme le bash dispose de plusieurs avantages :</p>
<ul>
<li style="text-align:justify;">langage interprété, il est facile de trouver les erreurs et de les traiter</li>
<li style="text-align:justify;">modification rapide sans besoin de recompiler</li>
<li style="text-align:justify;">langage orienté chaîne de caractères (pas de pointeurs), moins de risque d’avoir des erreurs d’adressage.</li>
<li style="text-align:justify;">prototypage rapide d’application, il est facile de composer des programmes avec les commandes existantes et l’utilisation des tubes et substitution dans l’environnement Unix</li>
<li style="text-align:justify;">langage “glu”: on peut connecter des composants écrits dans des langages différents. Ils doivent juste respecter certains standards :<ul>
<li style="text-align:justify;">lire sur l’entrée standard</li>
<li style="text-align:justify;">accepter des arguments et options éventuels,</li>
<li style="text-align:justify;">écrire ses résultats sur la sortie standard</li>
<li style="text-align:justify;">écrire les messages d’erreurs sur la sortie dédiée au erreur.</li>
</ul>
</li>
</ul>
<p style="text-align:justify;">Voyons maintenant certains inconvénients des shells :</p>
<ul>
<li style="text-align:justify;">La syntaxe est “ésotérique” et d’accès difficile pour les débutants</li>
<li style="text-align:justify;">Suivant le contexte, l’ajout ou l’oubli d’un espace peut provoquer des erreurs de syntaxe ou de traitement</li>
<li style="text-align:justify;">Plusieurs syntaxes pour implanter la même fonctionnalité (principalement à cause de la compatibilité ascendante avec le Bourne Shell</li>
<li style="text-align:justify;">Le sens de certains caractères spéciaux, comme les parenthèses, change avec le contexte, elle peuvent définir :<ul>
<li style="text-align:justify;">une liste de commandes</li>
<li style="text-align:justify;">une définition de fonction</li>
<li style="text-align:justify;">imposer un ordre d’évaluation</li>
<li style="text-align:justify;">une expression arithmétique</li>
</ul>
</li>
</ul>
<p style="text-align:justify;">Si vous voulez connaître le shell qui tourne actuellement, utilisez la commande ps, et si vous voulez connaître la version du bash :<br><code>bash -- version</code></p>
<h1 style="text-align:justify;">Variables</h1>
<p style="text-align:justify;">Ils existent différents types de variables utilisables dans le shell. Elles sont identifiées par un nom (suite de lettres, chiffres, caractères espace<br>ou souligné ne commençant pas par un chiffre. la casse est gérée). On peut classer 3 groupes de variables :</p>
<ul>
<li style="text-align:justify;">utilisateurs (ex: a, valeur)</li>
<li style="text-align:justify;">prédéfinies par le shell (ex; PS1, PATH, REPLY, IFS, HOME)</li>
<li style="text-align:justify;">prédéfinies pour les commandes unix (ex: TERM)</li>
</ul>
<p style="text-align:justify;">Pour affecter une variable, on peut utiliser l’opérateur = ou bien la commande interne read (pour demander une saisie utilisateur)</p>
<h2 style="text-align:justify;">Les variables locales :</h2>
<p style="text-align:justify;">Elles ne sont disponibles que dans l’instance du shell dans lesquelles elles ont été créées. (Elles ne sont pas utilisées par les commandes dans ce shell). Par défaut une variable est créée en tant que variable locale, on utilise couramment des lettres minuscules pour nommer ses variables locales.<br>Exemple : <code>mavariablelocale = 1</code></p>
<h2 style="text-align:justify;">Les constantes :</h2>
<p style="text-align:justify;">Une constante est une variable en lecture seul d’une certaine manière, elle n’a pas pour but d’être modifié dans le programme (d’où son nom). Pour créer une constante, vous pouvez utiliser la commande declare -r.<br>Exemple: <code>declare -r pi=3.14159</code></p>
<h2>Les variables d’environnement :</h2>
<p style="text-align:justify;">Les variables d’environnement existent dans le shell pour lequel elles sont créées, mais aussi pour toutes les commandes qui sont utilisées dans ce shell. On utilise couramment des majuscules pour nommer ses variables d’environnement.<br><strong>Exemple1 : Transformer une variable</strong></p>
<pre><code class="language-plaintext">ENVVAR=10 #Création d’une variable locale
export ENVVAR #Transforme la variable locale en variable d’environnement</code></pre>
<p style="text-align:justify;"><strong>Exemple 2: Créer une variable d’environnement</strong></p>
<pre><code class="language-plaintext">export ENVVAR2 = 11 # Première solution
declare -x ENVVAR3 = 12 # Deuxième solution
typeset -x ENVVAR4 = 13 # Troisième solution</code></pre>
<h2 style="text-align:justify;">Commandes utiles pour les variables :</h2>
<ul>
<li style="text-align:justify;"><code>echo</code> : Vous pouvez utiliser la commande echo si vous souhaitez connaître le contenu d’une variable.</li>
</ul>
<p style="text-align:justify;">Exemple : <code>echo $PATH</code> permettra d’afficher le contenu de la variable d’environnement PATH qui contient les chemins de fichier de<br>commande dans le shell.</p>
<pre><code class="language-plaintext">$ set param1 param2
$ echo $1
param1
$ set --
$ echo $1
$ #on a perdu les valeurs</code></pre>
<p style="text-align:justify;">Pour connaître le nombre de variables de position, il existe une variable spéciale $#</p>
<ul>
<li style="text-align:justify;"><code>shift</code> : permet de décaler les variables de position (sans toucher au $0)</li>
</ul>
<pre><code class="language-plaintext">$ set a b c d e f g h i j # param 1 2 3 4 5 6 7 8 9
$ echo $1 $2 $#
a b 9
$ shift 2 # variable deviennent c d e f g h i j
$ echo $1 $2 $#
c d 7</code></pre>
<p style="text-align:justify;">L’utilisation du shift sans argument équivaut à faire un <code>shift 1</code></p>
<ul>
<li style="text-align:justify;"><code>unset</code> : permet de supprimer une variable</li>
</ul>
<pre><code class="language-plaintext">$ set myvar=1
$ echo $myvar
1
$ unset myvar
$ echo $myvar
$</code></pre>
<p>&nbsp;</p>
<h1 style="text-align:justify;">Mon premier bash</h1>
<pre><code class="language-plaintext">#!/bin/bash
echo “Nom du programme : $0”
echo “Nombre d’arguments : $#”
echo “Source : $1”
echo “Destination $2”
cp $1 $2</code></pre>
<p>&nbsp;</p>
<pre><code class="language-plaintext">$ chmod u+x monpremierbash.sh
$ monpremierbash.sh /etc/passwd /root/copiepasswd
Nom du programme : ./monpremierbash.sh
Nb d’arguments : 2
Source : /etc/passwd
Destination : /root/copiepasswd</code></pre>
<p>&nbsp;</p>
<pre><code class="language-plaintext">$ set un deux trois quatre
$ echo $* # affiche tous les arguments
un deux trois quatre
$ echo $@ # affiche tous les arguments
un deux trois quatre
$ set un “deux trois” quatre # testons avec 3 paramètres et des guillemets
$ set “$*” # équivalent à set “un deux trois quatre”
$ echo $#
1
$ echo $1
un deux trois quatre
$ set un “deux trois” quatre # testons $@ avec 3 paramètres et des guillemets
$ set “$@” # équivalent à set “bonjour” “deux trois” “quatre”
$ echo $#
3
$ echo $2
deux trois</code></pre>
<p>Si dans un bash on souhaite supprimer les ambiguïtés d’interprétation des paramètres de position, on utilise le ${paramètre}, comme dans l’exemple suivant.</p>
<p><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">$ x=bon
$ x1=jour
$ echo $x1
jour
$ echo ${x}1
bon1
$ set un deux trois quatre cinq six sept huit neuf dix onze douze
$ echo $11
un1
$ echo ${11}
onze</code></pre>
<h1 style="text-align:justify;">Indirections</h1>
<p style="text-align:justify;">Bash offre la possibilité d’obtenir la valeur d’une variable v1 dont le nom est contenu “<code>v1</code>” dans une autre variable <code>mavar</code>. Il suffit pour cela d’utiliser la syntaxe de substitution : <code>${!mavar}</code>.</p>
<p style="text-align:justify;"><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">$ var=v1
$ v1=un
$ echo ${!var}
un</code></pre>
<p style="text-align:justify;">Ce mécanisme, appelé indirection, permet d’accéder de manière indirecte et par conséquent de façon plus souple, à la valeur d’un deuxième objet. Voyons un autre exemple d’utilisation :</p>
<p style="text-align:justify;"><strong>Exemple d’un fichier indir :</strong></p>
<pre><code class="language-plaintext">#!/bin/bash
agePierre=10
ageJean=20
read -p “Quel âge (Pierre ou Jean) voulez-vous connaître ? “ prenom
rep=age$prenom #construction du nom de la variable
echo ${!rep}
$ indir
Quel âge (Pierre ou Jean) voulez-vous connaître ? Pierre
10
$ indir
Quel âge (Pierre ou Jean) voulez-vous connaître ? Jean
20</code></pre>
<p style="text-align:justify;">Ce mécanisme s’applique également aux deux autres types de paramètres : les paramètres de position et les paramètres spéciaux ($1, $2, , ...)</p>
<h1 style="text-align:justify;">Résultats, Code de retour et opérateur sur les code de retour</h1>
<p style="text-align:justify;">Il ne faut pas confondre le résultat d’une commande et son code de retour : le résultat correspond à ce qui est écrit sur sa sortie standard; le code de retour indique uniquement si l’exécution de la commande s’est bien effectuée ou non. Parfois, on est intéressé uniquement par le code de retour d’une commande et non par les résultats qu’elle produit sur la sortie standard ou la sortie d’erreur.</p>
<p style="text-align:justify;"><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">$ grep toto pass &gt; /dev/null 2&gt;&amp;1 #=&gt; ou bien : grep toto pass &amp;&gt;/dev/null
$ echo $?
1 #=&gt; on en déduit que la chaîne toto n’est pas présente dans pass</code></pre>
<p style="text-align:justify;">Les opérateurs <code>&amp;&amp;</code> et <code>||</code> autorisent l’exécution conditionnelle d’une commande cmd suivant la valeur qu’a pris le code de retour de la dernière commande précédemment exécutée.</p>
<p style="text-align:justify;"><strong>Exemple pour &amp;&amp; :</strong></p>
<pre><code class="language-plaintext">$ grep toto pass &gt; /dev/null 2&gt;&amp;1 #=&gt; ou bien : grep toto pass &amp;&gt;/dev/null
$ echo $?
1 #=&gt; on en déduit que la chaîne toto n’est pas présente dans pass</code></pre>
<p style="text-align:justify;">La chaîne de caractères daemon est présente dans le fichier <code>pass</code>, le code de retour renvoyé par l’exécution de <code>grep</code> est <code>0</code>; par conséquent, la commande <code>echo</code> est exécutée.</p>
<p style="text-align:justify;"><strong>Exemple pour || :</strong></p>
<pre><code class="language-plaintext">$ ls pass tutu
ls : impossible d’accéder à tutu: Aucun fichier ou dossier de ce type pass
$ rm tutu || echo tutu non effacé
rm : impossible de supprimer tutu: Aucun fichier ou dossier de ce type
tutu non effacé</code></pre>
<p>Le fichier tutu n’existant pas, la commande <code>rm tutu</code> affiche un message d’erreur et produit un code de retour différent de <code>0</code>; la commande interne <code>echo</code> est exécutée.</p>
<p><strong>Exemple combiné || et || :</strong></p>
<pre><code class="language-plaintext">$ ls pass || ls tutu || echo fin aussi
pass</code></pre>
<p style="text-align:justify;">Le code de retour <code>ls pass</code> est égal à <code>0</code> car <code>pass</code> existe, la commande<code> ls tutu</code> ne sera pas exécutée. D’autre part le code de retour de l’ensemble <code>ls pass || ls tutu</code> est le code de retour de la dernière commande exécutée, c’est-à-dire <code>0</code> (<code>ls pass</code>). Donc <code>echo</code> fini aussi n’est pas exécutée.</p>
<p style="text-align:justify;"><strong>Exemple combiné &amp;&amp; et || :</strong></p>
<pre><code class="language-plaintext">$ ls pass || ls tutu || echo suite et &amp;&amp; echo fin
pass
fin</code></pre>
<p>La commande <code>ls pass</code> a un code de retour égal à 0, donc la commande <code>ls tutu</code> ne sera pas exécutée; le code de retour de l’ensemble <code>ls pass || ls tutu</code> sera donc égal à <code>0</code>. La commande <code>echo</code> suite et n’est pas exécutée donc le code de retour de l’ensemble reste <code>0</code> <code>echo fin</code> sera donc exécutée.</p>
<h1 style="text-align:justify;">Boucles et structure de contrôle</h1>
<h2 style="text-align:justify;">Case, structure de choix multiple</h2>
<p style="text-align:justify;"><strong>Syntaxe :</strong></p>
<pre><code class="language-plaintext">case mot in
[modele [ | modele] ...) suite de commandes ;; ] ...
esac</code></pre>
<p style="text-align:justify;">Le shell va étudier la valeur de mot puis la comparer séquentiellement à chaque modèle. Quand un modèle correspond à mot, la suite de commandes associée est exécutée, terminant l’exécution de la commande interne case. Les mots case et esac sont des mots-clés; ils doivent être le premier mot d’une commande. La suite des commandes doit se terminer par 2 caractères ; collés de manière à ce qu’il n’y ait pas d’ambiguïté avec l’enchaînement séquentiel de commande cmd1; cmd2; etc. Quand au modèle , il peut-être construit à l’aide de caractères et expressions génériques de bash (*, . , [], etc.). Dans ce contexte le symbole <code>|</code> signifiera OU. Pour indiquer le cas par défaut (si aucun des autres ne survient) on utilisera le modèle <code>*</code>. Il doit être placé en dernier modèle. Le code de retour de la commande composée case est égal à <code>0</code>, si aucun modèle n’a pu correspondre à la valeur de mot. Sinon, c’est celui de la dernière commande exécutée de suite de commandes.</p>
<p style="text-align:justify;"><strong>Exemple 1: Programme shell oui affichant OUI si l’utilisateur a saisi le caractère o ou O</strong></p>
<pre><code class="language-plaintext">#!/bin/bash
read -p “Entrez votre réponse : “ rep
case $rep in
o|O ) echo OUI ;;
* ) echo Indefini
esac</code></pre>
<p style="text-align:justify;"><strong>Exemple 2 : Programme shell nombre prenant une chaîne de caractères en argument, et qui affiche cette chaîne si elle est constituée d’une suite de chiffres. ([:digit:] , [:upper:], [:lower:], [:alnum:]</strong></p>
<pre><code class="language-plaintext">#!/bin/bash
# on autorise l’utilisation des expressions générique
shopt -s extglob
case $1 in
+([[:digit:]]) ) echo $1 est une suite de chiffres ;;
esac</code></pre>
<p style="text-align:justify;"><strong>Exemple 3 : Si l’on souhaite ignorer la casse on peut modifier le flash de shopt</strong></p>
<pre><code class="language-plaintext">#!/bin/bash
read -p “Entrez un mot : “ mot
shopt -s nocasematch
case $mot in
oui ) echo Vous avez écrit oui” ;;
* ) echo “$mot n’est pas le mot oui” ;;
esac</code></pre>
<h2 style="text-align:justify;">While</h2>
<p style="text-align:justify;">La commande interne <code>while</code> correspond à l’itération faire - tant que’ présente dans de nombreux langage de programmation.<br><strong>Syntaxe :</strong></p>
<pre><code class="language-plaintext">while suite_cmd1
do
suite_cmd2
done</code></pre>
<p style="text-align:justify;">La suite de commandes <code>suite_cmd1</code> est exécutée, si son code de retour est égal à <code>0</code>, alors la suite de commande <code>suite_cmd2</code> est exécutée, puis <code>suite_cmd1</code> est re-exécutée. Si son code de retour est différent de <code>0</code>, la suite se termine. L’originalité de cette méthode est que le test ne porte pas sur une condition booléenne, mais sur le code de retour issu de l’exécution d’une suite de commandes. Une commande <code>while</code>, comme toutes commandes internes, peut être écrite directement sur la ligne de commande.</p>
<p style="text-align:justify;"><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">$ while who | grep root&gt; /dev/null
&gt; do
&gt; echo “Utilisateur root est connecté”
&gt; sleep 5
&gt; done
Utilisateur root est connecté
Utilisateur root est connecté
Utilisateur root est connecté
^C
$</code></pre>
<p style="text-align:justify;"><br><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">$ while : #=&gt; Boucle infinie
&gt; do
&gt; who | cut -d’ -f1 &gt; fic #=&gt; Traitement à effectuer
&gt; sleep 300 #=&gt; Temporiser
&gt; done &amp;
[1] 1123 #=&gt; pour arrêter l’exécution kill -15 1123
$</code></pre>
<p style="text-align:justify;">On peut parfois utilisée la commande <code>while</code> pour lire un fichier texte. La lecture se fait alors ligne par ligne. Pour cela, il suffit de :</p>
<ul>
<li style="text-align:justify;">placer la commande <code>read</code> dans <code>suite_cmd1</code></li>
<li style="text-align:justify;">de placer les commandes de traitement de la ligne courante dans <code>suite_cmd2</code></li>
<li style="text-align:justify;">de rediriger l’entrée standard de la commande <code>while</code> avec le fichier lire</li>
</ul>
<p style="text-align:justify;"><strong>Syntaxe :</strong></p>
<pre><code class="language-plaintext">while read [var1 ...]
do
Commandes de traitements
done &lt; fichier à lire</code></pre>
<p><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">#!/bin/bash
who &gt; tmp
while read nom divers
do
echo $nom
done &lt; tmp
rm tmp</code></pre>
<p style="text-align:justify;">L’utilisation du <code>while</code> pour lire un fichier n’est pas très performante. On préférera en général utiliser une suite de filtre pour obtenir les résultats voulus (cut, awk, ...)</p>
<h1 style="text-align:justify;">Modificateur de chaîne</h1>
<h2 style="text-align:justify;">Échappement</h2>
<p style="text-align:justify;">Différents caractères particuliers servent en shell pour effectuer ses propres traitements (<code>$</code> pour la substitution, <code>&gt;</code> pour la redirection, <code>*</code> en joker). Pour utiliser ces caractères particuliers en tant que simple caractère, il faut les échapper en les précédant du caractère <code>\</code></p>
<p style="text-align:justify;"><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">$ ls
tata toto
$ echo *
tata toto
$ echo \*
*
$ echo \\
\</code></pre>
<p style="text-align:justify;">Autre particularité, le caractère <code>\</code> peut aussi échapper les retours à la ligne. On peut donc aller à la ligne sans exécuter la commande.<br>Comme nous l’avons déjà vu, les caractères <code></code> et <code></code> permettre une protection partielle, ou total <code>()</code> d’une chaîne de caractères.</p>
<p style="text-align:justify;"><strong>Exemple :</strong></p>
<pre><code class="language-plaintext">$ echo “&lt; * $PWD &gt;
&lt; * /root &gt;
$
$ echo “\”$PS2\””
&gt;
$ echo &lt; * $PWD “ &gt;
&lt; * $PWD “ &gt;
$ echo c’est lundi
&gt;
&gt;
cest lundi
$ echo c\’est lundi
c’est lundi
$ echo “c’est lundi”
c’est lundi</code></pre>
<h2 style="text-align:justify;">Chaîne de caractères longueur</h2>
<p style="text-align:justify;">Syntaxe : <code>${#paramètre}</code><br>Cette syntaxe permet d’obtenir la longueur d’une chaîne de caractères.</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ echo $PWD
/root
$ echo ${#PWD}
5
$ set “Bonjour à tous”
$ echo ${#1}
14
$ ls &gt; /dev/null
$ echo ${#?}
1 #=&gt; la longueur du code de retour (0) est de 1 caractère</code></pre><h2 style="text-align:justify;">Chaîne de caractères modificateur</h2><p style="text-align:justify;">On peut modifier les chaîne de caractères directement :<br><strong>Syntaxe :</strong><code> ${paramètre#modèle}</code> pour supprimer la plus <strong>courte</strong> sous-chaîne à gauche</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ echo $PWD
/home/christophe
$ echo ${PWD#*/}
home/christophe #=&gt; le premier caractère / a été supprimé
$ set “25b75b”
$ echo ${1#*b}
75b #=&gt; Suppression de la sous-chaîne 25b</code></pre><p style="text-align:justify;"><strong>Syntaxe: </strong><code>${paramètre##modèle}</code> pour supprimer la plus <strong>longue</strong> sous-chaîne à gauche</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ echo $PWD
/home/christophe
$ echo ${PWD##*/}
christophe #=&gt; suppression jusqu’au dernier caractère /
$ set “25b75b”
$ echo ${1##*b}
b</code></pre><p style="text-align:justify;">Pour la suppression par la droite, c’est la même chose en utilise le caractère % comme contrôle<br><strong>Syntaxe :</strong><br><code>${paramètre%modèle}</code> pour supprimer la plus courte sous-chaîne à droite<br><code>${paramètre%%modèle}</code> pour supprimer la plus longue sous-chaîne à droite</p><p style="text-align:justify;">On peut extraire une sous-chaîne également :<br><strong>Syntaxe:</strong><br><code>${paramètre:ind}</code> : extrait la valeur de paramètre de la sous-chaîne débutant à l’indice ind.<br><code>${paramètre:ind:nb}</code> : extrait nb caractères à partir de l’indice ind</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ lettres=”abcdefghijklmnopqrstuvwxyz”
$ echo {$lettre:20}
uvwxyz
$ echo {$lettre:3:4}
defg</code></pre><p style="text-align:justify;">Remplacement dans une sous-chaîne<br><strong>Syntaxe:</strong><br><code>${paramètre/mod/ch} </code>bash recherchera dans paramètre la plus longue sous-chaîne satisfaisant le modèle mod puis remplacera cette sous-chaîne par<br>la chaîne ch. Seule la première sous-chaîne trouvée sera remplacée. mod peut être des caractères ou expressions génériques.<br><code>${paramètre//mod/ch}</code> : Pour replacer toutes les occurrences et pas seulement la première<br><code>${paramètre/mod/}</code> :<br><code>${paramètre//mod/}</code> : Supprime au lieu de remplacer</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ v=totito
$ echo {$v/to/lo}
lotito
$ echo {$v//to/lo}
lotilo</code></pre><h1 style="text-align:justify;">Structure de contrôle for et if</h1><h2 style="text-align:justify;">Itération et for</h2><p style="text-align:justify;"><strong>Syntaxe :</strong></p><pre><code class="language-plaintext">for var
do
suite_de_commandes
done
Syntaxe 2:
for var in liste_mots
do
suite_de_commandes
done</code></pre><p>Dans la première forme, la variable var prend successivement la valeur de chaque paramètre de position initialisé</p><p><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ cat for_args.sh
#!/bin/bash
for i
do
echo $i
echo “next ...”
done
$ ./for_args.sh first second third
first
next ...
second
next ...
third
next ...</code></pre><p><strong>Exemple 2 :</strong></p><pre><code class="language-plaintext">$ cat for_set.sh
#!/bin/bash
set $(date)
for i
do
echo $i
done
$ ./for_set.sh
samedi
29
Juin
2019,
12:09:21
(UTC+0200)</code></pre><p>La deuxième syntaxe permet à var de prendre successivement la valeur de chaque mot de liste_mots.</p><p><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ cat for_liste.sh
#!/bin/bash
for a in toto tata
do
echo $a
done</code></pre><p>Si liste_mots contient des substitutions, elles sont préalablement traitées par bash.</p><p><strong>Exemple 2 :&nbsp;</strong></p><pre><code class="language-plaintext">$ cat affiche_ls.sh
#!/bin/bash
for i in /tmp ${pwd}
do
echo “ --- $i ---”
ls $i
done
$ ./affiche_ls.sh
--- /tmp ---
toto tutu
--- /home/christophe
for_liste.sh affiche_ls.sh alpha tmp</code></pre><h2 style="text-align:justify;">If et le choix</h2><p style="text-align:justify;">La commande interne if implante le choix alternatif</p><p style="text-align:justify;"><strong>Syntaxe :</strong></p><pre><code class="language-plaintext">if suite_commande1
then
suite_commande2
[elif suite_de_commandes; then suite_de_commande] ...
[else suite_de_commandes]
fi</code></pre><p style="text-align:justify;">Le principe de fonctionnement est le même que pour le <code>for</code>, on test la valeur de retour d’une commande plutôt qu’une valeur booléenne simple. Donc dans notre exemple, <code>suite_commande2</code> est exécuté, si <code>suite_commande1</code> renvoi <code>0</code> (pas d’erreur). Sinon c’est <code>elif</code> ou bien <code>else</code> qui sera exécuté.</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ cat rm1.sh
#!/bin/bash
if rm “$1” 2&gt; /dev/null
then echo $1 a été supprimé
else echo $1 n\’a pas été supprimé
fi
$ &gt;toto
$ rm1 toto
toto a été supprimé
$ rm1 toto
toto n’a pas été supprimé</code></pre><p style="text-align:justify;">Lorsque <code>rm1 toto</code> est lancé, si le fichier <code>toto</code> est effaçable, il le sera, et la commande <code>rm</code> renvoi <code>0</code>.<br>Notez qu’il est possible d’imbriquer les <code>if</code> ensembles.</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">if...
then....
if...
then ...
fi
else ...
fi</code></pre><h2 style="text-align:justify;">Tests</h2><p style="text-align:justify;">Dans les bash, vous retrouverez souvent une notation de commande interne <code>[[</code> souvent utilisé avec le <code>if</code>. Elle permet l’évaluation de d’expressions conditionnelles portant sur des objets aussi différents que les permissions sur une entrée, la valeur d’une chaîne de caractères ou encore l’état d’une option de la commande interne set.</p><p style="text-align:justify;"><strong>Syntaxe :</strong> <code>[[ expr_conditionelle ]]</code></p><p style="text-align:justify;">Les deux caractères crochets doivent être collés et un caractère séparateur doit être présent de part et d’autre de <code>expr_conditionelle</code>. Les mots <code>[[</code> et <code>]]</code> sont des mots-clés. On a vu que le <code>if</code> fonctionne selon la valeur de retour d’une commande, et pas d’un booléen, cette syntaxe permet “d'exécuter un test” qui renverra <code>1</code> si le test est vrai, <code>0</code> sinon. Si l’expression contient des erreurs syntaxique une autre valeur sera retournée. La commande interne <code>[[</code> offre de nombreuses expressions conditionnelles, c’est pourquoi seules les principales formes de <code>exp_conditionnelle</code> seront présentées, regroupées par catégories.</p><h2 style="text-align:justify;">Permission</h2><p style="text-align:justify;"><code>-r</code> entrée vraie si entrée existe et est accessible en lecture par le processus courant<br><code>-w</code> entrée vraie si entrée existe et est accessible en écriture par le processus courant<br><code>-x</code> entrée vraie si entrée existe et est accessible en exécutable par le processus courant ou si le répertoire entrée existe et</p><p style="text-align:justify;">le processus courant possède la permission de passage</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ echo coucou &gt; toto
$ chmod 200 toto
$ ls -l toto
--w- --- --- 1 christophe christophe 29 juin 1 14:04 toto
$
$ if [[ -r toto ]]
&gt; then cat toto
&gt; fi
$ =&gt; rien ne ce passe
$ echo $?
0 =&gt; code de retour de la commande interne if
$
MAIS
$ [[ -r toto ]]
$ echo $?
1 =&gt; code de retour de la commande interne [[</code></pre><h2 style="text-align:justify;">Type d’une entrée</h2><p style="text-align:justify;"><code>-f</code> entrée vraie si entrée existe et est un fichier ordinaire<br><code>-d</code> entrée vraie si entrée existe et est un répertoire</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ cat afficher.sh
#!/bin/bash
if [[ -f “$1” ]]
then
echo “$1” : fichier ordinaire
cat “$1”
elif [[ -d “$1” ]]
then
echo “$1” : répertoire
ls “$1”
else
echo “$1” : type non traité
fi
$ ./afficher
. : répertoire
afficher.sh test.sh toto alpha rm1.sh</code></pre><p style="text-align:justify;">Renseignement divers sur une entrée<br><code>-a</code> entrée vraie si entrée existe<br><code>-s</code> entrée vraie si entrée existe et sa taille est différente de 0 (un répertoire vide &gt; 0)<br>entrée 1 <code>-nt</code> entrée 2 vraie si entrée 1 existe et sa date de modification est plus récente que celle de entrée2<br>entrée1 <code>-ot</code> entrée 2 vraie si entrée1 existe et sa date de modification est plus ancienne que celle de entrée2</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ &gt; err
$
$ ls -l err
-rw-rw-r-- 1 christophe christophe 0 juin 29 14:30 err
$ if [[ -a err ]]
&gt; then echo err existe
&gt; fi
err existe
$ if [[ -s err ]]
&gt; then echo err n’est pas vide
&gt; else err est vide
&gt; fi
err est vide</code></pre><h2 style="text-align:justify;">Longueur d’une chaîne de caractère</h2><p style="text-align:justify;"><code>-Z</code> ch vraie si la longueur de ch est égale à 0<br>ch ou (<code>-n</code> ch) vraie si la longueur de ch est différente de 0<br>ch1 <code>&lt;</code> ch2 vraie si ch1 précède ch2<br>ch1 <code>&gt;</code> ch2 vraie si ch1 suit ch2<br>ch <code>==</code> mod vraie si la chaîne ch correspond au modèle mod<br>ch <code>!=</code> mod vraie si la chaîne ch ne correspond pas au modèle mod<br><code>-o</code> opt vraie si l’option interne opt est sur on</p><p style="text-align:justify;">Important : il existe un opérateur <code>=~</code> qui permet de mettre en correspondance une chaîne de caractères ch avec une expression<br>régulière.</p><p><strong>Exemple :</strong></p><pre><code class="language-plaintext">$a=01/01/2010
$[[ $a =~ [0-9]{2}\/[0-9]{2}\/[0-9]{2,4} ]]
$ echo $?
0
$ a=45/54/1
$[[ $a =~ [0-9]{2}\/[0-9]{2}\/[0-9]{2,4} ]]
$ echo $?
1</code></pre><h2 style="text-align:justify;">Expressions conditionnelles</h2><p style="text-align:justify;">( cond ) vraie si cond est vraie<br>! cond vraie si cond est fausse<br>cond1 &amp;&amp; cond 2 vraie si cond1 et 2 sont vraie, l’évaluation s’arrête si cond1 est fausse<br>cond1 || cond2 vraie si cond1 ou 2 sont vraie.</p><p style="text-align:justify;"><strong>Exemple :</strong></p><pre><code class="language-plaintext">$ ls -l /etc/at.deny
-rw-r----- 1 root daemon 144 oct. 25 2018 /etc/at.deny
$
$ if [[ ! ( -w /etc/at.deny || -r /etc/at.deny ) ]]
&gt; then
&gt; echo OUI
&gt; else
&gt; echo NON
&gt; fi
OUI</code></pre><p style="text-align:right;">Source : <a href="https://doc.ataxya.net">doc.ataxya.net</a></p>