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
informatique:linux:programmation_shell [2021/01/05 09:08] – [for] pteuinformatique:linux:programmation_shell [2023/10/02 13:35] (current) – [Lire depuis un fichier] pteu
Line 6: Line 6:
 Les différents shells peuvent avoir des fonctions sensiblement différentes voir incompatibles. Ce n'est pas le cas pour la majorité d'entre elles. Ici nous parlerons de [[https://fr.wikipedia.org/wiki/Bourne-Again_shell|bash]] car c'est le plus couramment utilisé. Les différents shells peuvent avoir des fonctions sensiblement différentes voir incompatibles. Ce n'est pas le cas pour la majorité d'entre elles. Ici nous parlerons de [[https://fr.wikipedia.org/wiki/Bourne-Again_shell|bash]] car c'est le plus couramment utilisé.
  
-Pour afficher la liste des options de bash il faut saisir ''bash -c "help set"''. Pour lire un script sans exécuter les commandes : ''bash -n''.+Pour afficher la liste des options de bash il faut saisir ''bash -c "help set"''. Pour lire un script sans exécuter les commandes (mode "dry-run) : ''bash -n''
 + 
 +Les mots d'une ligne suivants un ''#'' sont considérés comme des commentaires (ils ne sont pas interprétés) ; les commentaires multi-lignes sont encadrés de ''<nowiki>:'</nowiki>'' et ''<nowiki>'</nowiki>''.
  
   * ''. <CONFIG_FILE>'' => permet de faire un //include// (notez bien le point + espace ". ")   * ''. <CONFIG_FILE>'' => permet de faire un //include// (notez bien le point + espace ". ")
Line 38: Line 40:
 local VAR="pwet" local VAR="pwet"
 </code> </code>
 +<WRAP center round important 60%>
 +Les variables déclarées dans une fonction ont toujours une portée locale (elles sont détruites à la fin de la fonction), à moins qu'elles ne soient préalablement déclarées dans le script appelant.
 +</WRAP>
 +
  
 Pour déclarer une constante locale à une fonction : Pour déclarer une constante locale à une fonction :
Line 113: Line 119:
 </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 120: Line 127:
 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 125: Line 134:
   * ''${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 133: Line 143:
 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 164: Line 176:
 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 359: Line 377:
 </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).
 +
 +====Herestring====
 +
 +Dans la même veine que le heredoc, la herestring permet d'envoyer une chaîne de caractères dans une commande ; il peut d'agir d'une variable :
 +<code bash>
 +VAR="dad text"
 +cat <<< $VAR
 + dad text
 +
 +bc <<< 2*2
 + 4
 +</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 388: Line 432:
  
 ======Les fonctions====== ======Les fonctions======
 +
 +=====function=====
 +
 +Elles permettent de mutualiser le code afin qu'il soit appeler plusieurs fois sans avoir à le ré-écrire.
 +<code bash>
 +function mafonction() {
 +  echo "exécution de mafonction"
 +}
 +
 +# appelle de la fonction, plus bas dans le code
 +mafonction
 +</code>
 +A l'intérieur d'une fonction on peut utiliser des variables locales en les déclarant ''local VAR=""''. Pour envoyer un code de retour on utilise ''return'' (pas ''exit'' comme dans le script principal, sinon on quitte le script !).
 +
 +La variable bash ''$FUNCNAME'' permet d'afficher le nom de la fonction courante.
  
 =====pipe ("|")===== =====pipe ("|")=====
Line 420: Line 479:
 Pour afficher un texte avant la saisie on utilise ''-p'' ; on peut récupérer plusieurs saisie d'un seul coup : Pour afficher un texte avant la saisie on utilise ''-p'' ; on peut récupérer plusieurs saisie d'un seul coup :
 <code bash> <code bash>
-read -p "Quel est le numéro de ta CB ? Et le cryptogramme visuel de derrière ?" CARD_NUMBER CRYPTO+read -p "Quel est ton nom ?" NOM 
 +</code> 
 +Pour masquer la saisie, s'il s'agit d'un mot de passe par exemple, on utilise ''-s''
 +<code bash> 
 +read -s -p "Et ton numéro de CB ?" CARD_NUMBER
 </code> </code>
  
-Pour lire depuis un fichier :+====Lire depuis un fichier====
 <code bash> <code bash>
 read < fichier.txt read < fichier.txt
Line 430: Line 493:
 while read line; do while read line; do
   echo $line   echo $line
 +done < fichier.txt
 +</code>
 +
 +Pour lire mot par mot, si le fichier est formaté (par exemple s'il contient une liste de "nom prénom") :
 +<code bash>
 +while read nom prenom; do
 +  echo "nom=$nom ; prenom=$prenom"
 done < fichier.txt done < fichier.txt
 </code> </code>
Line 444: Line 514:
 done done
 </code> </code>
-Le premier exemple utilise une [[https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html#Process-Substitution|process substitution]], qui permet de référencer l'entrée (''>(list)'') ou la sortie (''<(list)'') d'une commande comme un fichier et non plus un flux ; le second un pipe, mais les 2 se valent.+Le premier exemple utilise une [[https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html#Process-Substitution|process substitution]], qui permet de référencer l'entrée (''>(list)'') ou la sortie (''<(list)'') d'une commande comme un fichieret non plus un flux ; le second un pipe, mais les 2 se valent. 
 + 
 +* : en réalité bash utilise réellement un fichier temporaire, la preuve : 
 +<code bash> 
 +$ echo <(echo foo) 
 +/dev/fd/63 
 + 
 +$ cat <(echo foo) 
 +foo 
 + 
 +$ xargs echo < <(echo foo) 
 +foo 
 +</code> 
 +====Lire depuis une variable====
  
-Pour lire depuis une variable : 
 <code bash> <code bash>
 read <<< $var read <<< $var
 +</code>
 +
 +Seconde façon de faire, et plus adéquate si la variable contient des sauts de ligne :
 +<code bash>
 +ECHO="toto1 titi1\ntoto2 titi2"; echo -e "$ECHO" | while read a b; do echo "a=$a ; b=$b"; done
 + a=toto1 ; b=titi1
 + a=toto2 ; b=titi2
 </code> </code>
 ====== Expressions arithmétiques ====== ====== Expressions arithmétiques ======
Line 540: Line 629:
   * ''-O file'' : si le fichier nous appartient    * ''-O file'' : si le fichier nous appartient 
   * ''-G file'' : si le fichier appartient à notre groupe   * ''-G file'' : si le fichier appartient à notre groupe
 +
 +  * ''-t fd'' : vrai si //filedescriptor// fd est ouvert et se réfère à un terminal
  
 ====Chaînes de caractères==== ====Chaînes de caractères====
Line 871: Line 962:
 </code> </code>
  
 +=====trim (suppression des espaces dans une chaîne)=====
 +
 +bash ne possède pas de fonction prédéfinie pour "trimmer" les chaînes de caractère. **trim** est une fonction, habituellement incluse dans les langages de programmation, permettant de supprimer les espaces parasites avant et après une chaîne : par exemple " cette chaîne" ou " celle-ci       ".
 +
 +Pour faire cette office il existe plusieurs possibilités d'afficher les cellules du tableau suivant sans les espaces :
 +<code bash>
 +arr=('foo bar' 'test@domain.com ' \
 +' test@domain.com ' '    test@domain.com         ')
 +</code>
 +
 +  * en utilisant la substitution de caractère dans les variables, en activant le //globbing étendu// (des motifs d'expressions régulières prédéfinis) (source: [[https://www.cyberciti.biz/faq/how-to-trim-leading-and-trailing-white-space-in-bash/|cyberciti.biz]]) :
 +<code bash>
 +shopt -s extglob                     # activation des extended glob
 +# (pour reconnaître [[:blank:]] qui définit l'ensemble des espaces et tabulations)
 +arr=( "${arr[@]/#+([[:blank:]])/}" ) # suppression des espaces de début de chaîne
 +arr=( "${arr[@]/%+([[:blank:]])/}" ) # suppression des espaces de fin de chaîne
 +</code>
 +
 +  * avec ''mapfile'' et ''<nowiki>set --</nowiki>'' (source: [[https://stackoverflow.com/questions/61081608/bash-remove-leading-and-trailing-spaces-in-array/61087835#61087835|stackoverflow]])
 +<code bash>
 +function trim() {
 + mapfile -t t_input<<<"$*"    # place chaque paramètre dans une cellule du tableau (un par ligne)
 + [[ ${#t_input[@]} -eq 0 ]] && { echo "Aucun texte à afficher"; exit 1; }
 + set -- ${t_input[@]}         # affecte chaque case du tableau à un paramètre ($1, $2, etc)
 + printf '%s\n' "$*"           # affiche chaque paramètre suivi d'un saut de ligne
 +}
 +trim "${arr[@]}"
 +</code>
 ====== Ressources ====== ====== Ressources ======
  
Line 877: Line 996:
   * [[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 !   * 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 !
 +  * [[https://google.github.io/styleguide/shellguide.html|Shell Style Guide]] by Google
 +  * [[https://betterdev.blog/minimal-safe-bash-script-template/|Minimal safe Bash script template]] (betterdev.blog)
 +  * [[https://github.com/pforret/bashew/blob/master/README.md|bashew]] / [[https://blog.forret.com/portfolio/bashful/|bashful]] : un outil de création de script bash et le blog de son auteur, Peter Forret
 +  * [[https://github.com/ralish/bash-script-template|bash-script-template]]
informatique/linux/programmation_shell.1609837684.txt.gz · Last modified: 2021/01/05 09:08 by pteu