User Tools

Site Tools


informatique:linux:programmation_shell

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
informatique:linux:programmation_shell [2020/01/08 10:52] – [Typage] pteuinformatique:linux:programmation_shell [2021/01/05 14:47] – [Manipulation des variables] :: pteu
Line 26: Line 26:
 </code> </code>
 On peut les manipuler sans les déclarer proprement au préalable ; mais on peut être clean et les définir (''declare VAR'') ou les supprimer (''unset VAR''). On peut les manipuler sans les déclarer proprement au préalable ; mais on peut être clean et les définir (''declare VAR'') ou les supprimer (''unset VAR'').
 +
 +Pour déclarer une variable non modifiable = en readonly (une constante) :
 +<code bash>
 +readonly CONST="constante"
 +# ou
 +declare -r CONST="constante"
 +</code>
  
 Par défaut une variable est globale et est vue dans le script (y compris ses fonctions) ; dans une fonction on peut déclarer des variables locales afin d'éviter les écrasements de variables globales non souhaités avec : Par défaut une variable est globale et est vue dans le script (y compris ses fonctions) ; dans une fonction on peut déclarer des variables locales afin d'éviter les écrasements de variables globales non souhaités avec :
Line 31: Line 38:
 local VAR="pwet" local VAR="pwet"
 </code> </code>
 +
 +Pour déclarer une constante locale à une fonction :
 +<code bash>
 +local -r CONST="constante locale"
 +
 +# ou en 2 lignes
 +local CONST="constante locale"
 +readonly CONST
 +
 +# marche aussi, puisque lorsque declare est invoqué dans une fonction,
 +#  la variable qui suit est déclarée localement
 +function test() {
 +  declare -r CONST="constante locale"
 +  }
 +</code>
 +C'est assez touffu je suis d'accord.
 +
 +
 +
 +
  
 ===== Tests de définition===== ===== Tests de définition=====
Line 75: Line 102:
 fi fi
 </code> </code>
 +
 +Pour plus de détails sur le pseudo-typage en bash, voir la fonction [[informatique:linux:commandes_linux#declare|declare]].
  
 ===== Manipulation des variables===== ===== Manipulation des variables=====
Line 84: Line 113:
 </code> </code>
 Sans les ''{}'', l'interpréteur présumera que la variable se nomme ''$REP_LOCAL_'' et non ''$REP_LOCAL''. Sans les ''{}'', l'interpréteur présumera que la variable se nomme ''$REP_LOCAL_'' et non ''$REP_LOCAL''.
-  * on peut tronquer une variable : ''${VAR:POS}'' => renvoie le contenu à partir de la position POS (comptabilisée à partir de 0). Si POS est négative (il faut la mettre entre parenthèses), on compte à partir de la fin de la chaine.+  * on peut tronquer une variable : ''${VAR:POS}'' => renvoie le contenu de VAR à partir de la position POS (comptabilisée à partir de 0). Si POS est négative (il faut la mettre entre parenthèses), on compte à partir de la fin de la chaine.
   * ''${VAR:POS:LONG}'' : renvoie la sous-chaine de longueur LONG à partir de la position POS   * ''${VAR:POS:LONG}'' : renvoie la sous-chaine de longueur LONG à partir de la position POS
 +  * Si on omet POS : ''${VAR::LONG}'' permet de supprimer les caractères suivants la position LONG ; si LONG est négatif, on part de la la fin de la chaine.
 <code bash> <code bash>
 VAR=undeuxtroisquatre VAR=undeuxtroisquatre
Line 91: Line 121:
 echo ${VAR:(-6)}       # quatre echo ${VAR:(-6)}       # quatre
 echo ${VAR:(-6):2}     # qu echo ${VAR:(-6):2}     # qu
 +echo ${VAR::2}         # un
 +echo ${VAR::(-6)}      # undeuxtrois
 </code> </code>
  
Line 96: Line 128:
   * ''${VAR#PAT}'' : supprime la plus __courte__ chaine répondant à la pattern PAT en partant du début de celle-ci ; on peut partir de la fin de la chaine avec ''%'' à la place de ''#''   * ''${VAR#PAT}'' : supprime la plus __courte__ chaine répondant à la pattern PAT en partant du début de celle-ci ; on peut partir de la fin de la chaine avec ''%'' à la place de ''#''
   * ''${VAR##PAT}'' : supprime la plus __longue__ chaine répondant à la pattern PAT (idem : ''<nowiki>%%</nowiki>'' pour partir de la fin)   * ''${VAR##PAT}'' : supprime la plus __longue__ chaine répondant à la pattern PAT (idem : ''<nowiki>%%</nowiki>'' pour partir de la fin)
-  * ''${VAR/PAT/SUBST}'' pour remplacer par SUBST la première occurrence du contenu de VAR répondant à la pattern PAT ; respectivement ''<nowiki>//</nowiki>'' pour toutes les occurrences. On peut partir du début ''#'' (par défaut) ou de la fin de la chaine ''%'', mais c'est dans tous les cas le motif le plus grand qui sera remplacer (pas de ''##'' ni ''<nowiki>%%</nowiki>'').+  * ''${VAR/PAT/SUBST}'' pour remplacer par SUBST la première occurrence du contenu de VAR répondant à la pattern PAT ; respectivement ''<nowiki>//</nowiki>'' pour toutes les occurrences. 
 +  * On peut limiter le remplacement aux seuls préfixe ''${VAR/#PAT/SUBST}'' ou suffixe ''${VAR/%PAT/SUBST}'', mais c'est dans tous les cas le motif le plus grand qui sera remplacé (pas de ''##'' ni ''<nowiki>%%</nowiki>'').
 <code bash> <code bash>
 VAR=undeuxtroisquatre VAR=undeuxtroisquatre
Line 104: Line 137:
 echo ${VAR/trois/3}    # undeux3quatre echo ${VAR/trois/3}    # undeux3quatre
 echo ${VAR//e/E}       # undEuxtroisquatrE echo ${VAR//e/E}       # undEuxtroisquatrE
 +echo ${VAR/#un/1}      # 1deuxtroisquatre
 +echo ${VAR/%q*/4}      # 1deuxtroisquatre
 </code> </code>
  
Line 125: Line 160:
   * ''$!'' renvoie le PID de la dernière commande   * ''$!'' renvoie le PID de la dernière commande
   * ''$?'' renvoie le retour (code d'erreur par exemple) de la dernière commande   * ''$?'' renvoie le retour (code d'erreur par exemple) de la dernière commande
 +  * ''$-'' renvoie la liste des paramètres courts du shell. Pour les interpréter, saisir ''help set'' dans le shell.
  
   * ''IFS="\n"'' (Internal Field Separator) le séparateur de champ est "ENTER" (utilisée par la commande read)   * ''IFS="\n"'' (Internal Field Separator) le séparateur de champ est "ENTER" (utilisée par la commande read)
   * ''$PWD'' renvoie le chemin du shell depuis lequel est lancé le script (équivalent à pwd) ; c'est complémentaire de ''$0''   * ''$PWD'' renvoie le chemin du shell depuis lequel est lancé le script (équivalent à pwd) ; c'est complémentaire de ''$0''
- 
  
  
Line 135: Line 170:
 Les enregistrements commencent à l'index 0. Ainsi pour récupérer le contenu de la 5ème case on doit utiliser l'index 4. Les enregistrements commencent à l'index 0. Ainsi pour récupérer le contenu de la 5ème case on doit utiliser l'index 4.
  
-  * ''TAB=( un deux trois )'' : définition d'un tableau de 3 cases +  * ''TAB=( un deux trois )'' : définition et remplissage d'un tableau de 3 cases 
-  * ''TAB[0]=val'' : affectation du premier enregistrement du tableau TAB +  * ''TAB[0]=UN'' : affectation du premier enregistrement du tableau TAB 
-  * ''${TAB[0]}'' : contenu du premier enregistrement du tableau TAB +  * ''${TAB[0]}'' ou ''$TAB'' : contenu du premier enregistrement du tableau TAB ("UN") 
-  * ''$TAB'' : équivalent de ''${TAB[0]}'' +  * ''${!TAB[@]}'' liste les indices des cases du tableau ("0 1 2") 
-  * ''${TAB[*]}'' ou ''${TAB[@]}'' : désigne l'ensemble des enregistrements du tableau TAB+  * ''${TAB[-1]}'' dernier élément du tableau ("trois") 
 +  * ''${TAB[*]}'' ou ''${TAB[@]}'' : désigne l'ensemble des enregistrements du tableau TAB ("un deux trois"
 +  * ''${TAB[@]:1:2}'' : désigne un intervalle de case ; entre celle d'indice 1 (TAB[1]) jusqu'à la 2nde lue ("deux trois"
 +  * ''TAB=("${TAB[@]}" "quatre")'' ou ''TAB+=("quatre")'' : push (ajout d'un élément à la fin du tableau) 
 +  * ''unset TAB[3]'' : supprimant la 4ème case 
 +  * ''TAB=("${TAB[@]/trois/}'' : suppression par expression régulière de la 2ème case ${TAB[2]} 
 +  * ''TAB=($(cat FILENAME))'' : remplir le tableau avec chaque mot du fichier
  
 Comme pour les variables classiques, on peut récupérer la longueur en le précèdent de ''#'' : Comme pour les variables classiques, on peut récupérer la longueur en le précèdent de ''#'' :
Line 153: Line 194:
 trois trois
 </code> </code>
 +
 +Exemple de découpage d'une chaîne dans un tableau, avec comme séparateur ";" :
 +<code bash>
 +CHAINE='17;8 23;9'
 +IFS=";"                       # définition du séparateur
 +read -a TAB <<<"$CHAINE"
 +echo "${#TAB[@]}"              # affiche de la taille du tableau (nombre de cellule)
 + 3
 +printf '%s\n' "${TAB[@]}"      # affichage du contenu du tableau cellule par cellule
 + 17
 + 8 23
 + 9
 +</code>
 +
 ====Tableau à 2 dimensions==== ====Tableau à 2 dimensions====
  
-Ça n'eût pas existé pas sous bash :). Mais on peut l'émuler en créant un tableau associatif (qui, à une clé fait correspondre un contenu), en codant la clé pour émuler 2 dimensions. Exemple : pour émuler un tableau de 2 x 3 cases :+Ça n'eût pas existé sous bash :). Mais on peut l'émuler en créant un tableau associatif (qui, à une clé fait correspondre un contenu), en codant la clé pour émuler 2 dimensions. Exemple : pour émuler un tableau de 2 x 3 cases :
 <code bash> <code bash>
 # déclaration d'un tableau associatif T # déclaration d'un tableau associatif T
Line 177: Line 232:
 </code> </code>
  
 +====Tableau associatif====
  
 +Créer et utiliser un vrai tableau associatif :
 +<code bash>
 +declare -A TA=([cle1]=valeur1 ["cle 2"]="valeur 2" [cle3]=valeur3)
 +echo "${TA[cle1]}"
 +# valeur1
 +
 +# Parcourir le tableau
 +for cle in "${!TA[@]}"; do
 +   echo "cle=$cle ; val=${TA[$cle]}"
 +done
 +#cle=cle 2 ; val=valeur 2
 +#cle=cle3 ; val=valeur3
 +#cle=cle1 ; val=valeur1
 +</code>
 +
 +Pour connaitre la taille de ce tableau : ''${#TA[@]}'' (3 dans cet exemple).
 =====getopts : analyse des arguments d'un script===== =====getopts : analyse des arguments d'un script=====
  
Line 299: Line 371:
 </code> </code>
 Ainsi on conserve les erreurs de chaque exécution du programme. Ainsi on conserve les erreurs de chaque exécution du programme.
 +
 +====Heredoc====
 +
 +Un document "ici-même" (traduction française de qualitaÿ) est une manière de saisir une chaîne de caractères en conservant l'indentation et les sauts de ligne dans un interpréteur de commande. C'est utile pour les longs textes sur plusieurs lignes qui sont alors beaucoup plus lisibles dans le code. On précède ledit texte par un double chevron ''<nowiki><<</nowiki>'' suivi d'un délimiteur arbitraire puis par un saut de ligne ; la fin de la saisie du texte sera marquée par une ligne contenant uniquement le délimiteur (donc suivi d'un saut de ligne). Plus concrètement, si on choisit le délimiteur "EOF" :
 +<code bash>
 +cat <<EOF
 +Ce   texte
 + sera affiché tel quel
 +EOF
 +
 +</code>
 +
 +On peut utiliser la variante ''<nowiki><<-</nowiki>'' pour ignorer les tabulations de début de ligne (cela permet d'intenter le code).
 +
 +====Descripteurs de fichier additionnels====
  
 On peut utiliser les descripteurs 3 et plus également, en les initialisant pour ne pas générer d'erreur (ils ne le sont pas par défaut) : On peut utiliser les descripteurs 3 et plus également, en les initialisant pour ne pas générer d'erreur (ils ne le sont pas par défaut) :
Line 400: Line 487:
  
 Pour incrémenter une variable : plusieurs possibilités : Pour incrémenter une variable : plusieurs possibilités :
-  * ''<nowiki>z=`expr $z + 1`</nowiki>'' +  * ''z=`expr $z + 1`'' ou ''z=$(expr $z + 1)'' 
-  * ''<nowiki>z=$(($z+1))</nowiki>'' +  * ''<nowiki>z=$(($z+1))</nowiki>'' ou ''<nowiki>z=$((z+1))</nowiki>'' (entre doubles parenthèses, le $ est optionnel)
-  * ''<nowiki>z=$((z+1))</nowiki>'' (entre doubles parenthèses, le $ est optionnel)+
   * ''<nowiki>(( z += 1 ))</nowiki>''   * ''<nowiki>(( z += 1 ))</nowiki>''
  
Line 485: Line 571:
   * ''"str1" = "str2"'' : teste l'égalité des 2 chaînes   * ''"str1" = "str2"'' : teste l'égalité des 2 chaînes
   * ''"str1" != "str2"'' : teste la différence des 2 chaînes   * ''"str1" != "str2"'' : teste la différence des 2 chaînes
-  * ''"str1" =~ regex'' : teste si str1 matche l'expression régulière regex (doit être inclus dans une condition ''<nowiki>[[ .. ]]</nowiki>''+  * ''"str1" =~ regex'' : teste si str1 matche l'expression régulière regex (au format extended, comme ''grep -E'') ;  le test doit être inclus dans une condition ''<nowiki>[[ .. ]]</nowiki>'' et la chaine str1 doit être double-quotée. Si on utilise des groupes capturants (entre ''(..)'') dans la REGEX, on peut rappeler les matchs avec la variable tableau ''${BASH_REMATCH[x]}'', comme on le ferait avec \1, \2, \3 pour sed. Par exemple : 
 +<code bash> 
 +[[ "la réponse est 42" =~ ^.*([0-9]{2}).*$ ]] && echo "${BASH_REMATCH[1]} est la réponse" 
 +42 est la réponse 
 +</code>
   * ''-z str'' : vrai si chaîne de longueur nulle   * ''-z str'' : vrai si chaîne de longueur nulle
   * ''-n str'' : vrai si chaîne de longueur non nulle    * ''-n str'' : vrai si chaîne de longueur non nulle 
Line 497: Line 587:
   * ''n1 -le n2'' plus petit ou égal   * ''n1 -le n2'' plus petit ou égal
  
 +Comme il n'y a pas de typage en bash, pour tester si la valeur d'une variable est un nombre (entier) il faut réaliser le tester :
 +<code bash>
 +# Solution à base de REGEX
 +[[ $VAR =~ ^[0-9]+$ ]] || echo "VAR n'est pas un entier"
 +# NB : l'expression régulière ne doit pas être quotée,
 +#      ou doit être enregistrée dans une variable sinon ça ne matche pas
 +
 +# "auto-test" numérique :)
 +[ $VAR -eq $VAR ] 2>/dev/null || echo "VAR n'est pas un entier"
 +</code>
 ==== Opérateurs ==== ==== Opérateurs ====
   * ''!'' unaire de négation   * ''!'' unaire de négation
Line 544: Line 644:
 DEBUT=1 DEBUT=1
 FIN=5 FIN=5
-for (( i = $DEBUT; i <= $FIN; i++ )) 
- 
 # ne fonctionne pas : for i in {$DEBUT..$FIN} # ne fonctionne pas : for i in {$DEBUT..$FIN}
 +# fonctionne :
 +for (( i = $DEBUT; i <= $FIN; i++ ))
 </code> </code>
 +
 +On peut spécifier l'incrément qui vaut par défaut 1, avec : ''for i in {1..5..2}'' (ici incrément de 2).
  
 On peut aussi lui fournir une liste de mots : On peut aussi lui fournir une liste de mots :
Line 796: Line 898:
 </code> </code>
  
-====== Liens ======+====== Ressources ======
  
   * http://abs.traduc.org/abs-5.0-fr/index.html   * http://abs.traduc.org/abs-5.0-fr/index.html
   * http://www.gnu.org/software/bash/manual/bashref.html   * http://www.gnu.org/software/bash/manual/bashref.html
   * [[http://tldp.org/LDP/abs/html/index.html|Advanced Bash-Scripting Guide]]   * [[http://tldp.org/LDP/abs/html/index.html|Advanced Bash-Scripting Guide]]
 +  * https://www.shellcheck.net : super moulinette en ligne pour analyser un script et recommander des améliorations (exsite aussi en package Linux : ''shellcheck''). A utiliser sans modération !
informatique/linux/programmation_shell.txt · Last modified: 2023/10/02 13:35 by pteu