18 juillet 2018

Utiliser des accolades avec les noms de variables Unix

En langage shell Unix, utiliser des accolades avec les noms de variables est facultatif.
Mais outre le fait qu'elles facilitent la lecture, elles peuvent se révéler extrêmement utiles...

Les expressions ci dessous ont été reconnues en ksh (test réalisé sous AIX7).
Le bash sera plus riche en fonctionnalités (consultez par exemple http://wiki.bash-hackers.org/syntax/pe)


VAR="Ah"
echo "$VAR"
Ah
echo "$VARAhAh"

 Interprété comme une variable VARAhAh

echo "${VAR}AhAh" 
 Interprété comme une variable VAR + texte AhAh
AhAhAh

VAR=
echo "${VAR}"

 Contrôle de présence (NB : des caractères spéciaux dans le message peuvent poser problème)
echo "${VAR:?La variable VAR est vide}"
ksh: VAR: La variable VAR est vide
echo $?
1


 Affichage par défaut
echo "${VAR:-default}"
default
echo "${VAR}"


 Alimentation par défaut
echo "${VAR:=default}"
default
echo "${VAR}"
default



 Affichage alternatif (de remplacement)
echo "${VAR:+La variable VAR est alimentée}"
La variable VAR est alimentée


 NB : La syntaxe ${VAR?message}, ${VAR-default}, ${VAR=default} et  ${VAR+replace} agit de même si la variable est "unset"

 Longueur
echo ${#VAR}
7

Extraction d'une sous chaine (substring) :décalage(:longueur)

CDPLPH=PPHR9DE5

echo ${CDPLPH:0:5}
PPHR9
 

En cas de décalage négatif (ajouter un espace) l'extraction partira de la fin de la chaine

echo ${CDPLPH: -3}
DE5
echo ${CDPLPH: -3:2}
DE

 

IP=10.20.30.40

 Retirer le plus petit préfixe correspondant au motif (ex : '*.' signifie 'retirer les caractères avant le premier '.' celui-ci inclus)
 syntaxe de type 'ls' (cad '*' = n caractères quelconques et '?' = un caractère)
echo ${IP#*.}
20.30.40

 Retirer le plus grand préfixe correspondant au motif (ex : '*.' signifie 'retirer les caractères avant le dernier '.' celui-ci inclus)
echo ${IP##*.}
40


 Retirer le plus petit suffixe correspondant au motif (ex : '.*' signifie 'retirer les caractères après le dernier '.' celui-ci inclus)
echo ${IP%.*}
10.20.30

 Retirer le plus grand suffixe correspondant au motif (ex : '.*' signifie 'retirer les caractères après le premier '.' celui-ci inclus)
echo ${IP%%.*}
10


VAR=ABCDEF
  Retirer les 3 premiers caractères
echo "${VAR#???}"
DEF

  Retirer les 3 derniers caractères
echo "${VAR%???}"
ABC

  Substituer un motif
echo "${VAR//CD/cd}"
ABcdEF
 

Attention : préférez le le ksh 93 qui sera plus riche que le ksh 88

VAR="AABBCC";
echo ${VAR%%B*};
echo "${VAR: -3:2}";
echo "${VAR#???}";
echo "${VAR//A/D}"

Avec ksh88 🙁

AA
ksh: "${VAR: -3:2}": bad substitution
BCC
ksh: "${VAR//A/D}": bad substitution

Avec ksh93 🙂

AA
BC
BCC
DDBBCC

Tableaux

Ici l'indice est numérique mais ces tableaux acceptent des textes

Déclaration (ksh)
set -A TB
Déclaration et alimentation (ksh)
set -A TB 10 20 30 40
Alimentation d'un élément (l'indice commence a zéro)
TB[4]=50
ksh comme bash
i=0; for v in 10 20 30 40; do TB[$i]=$v; ((i++));done

 Affichage des éléments
echo ${TB[@]}
echo ${TB[*]}
10 20 30 40 50


 Affichage d'un élément
echo ${TB[2]}
30

 Longueur d'un l'élément
echo ${#TB[4]}
2


 Nombre d'éléments dans le tableau
echo ${#TB[*]}
5


 Sauvegarde puis modification du Internal Field Separator
oIFS="${IFS}"
IFS=","

 Effet sur l'affichage des listes
 Avec "${name[*]}" l'IFS intervient comme séparateur, pas avec "${name[@]}", ni en cas d'absence de quotes
echo ${TB[*]}
10 20 30 40 50
echo "${TB[*]}"
10,20,30,40,50

echo ${TB[@]}
10 20 30 40 50
echo "${TB[@]}"
10 20 30 40 50
IFS="${oIFS}"


 De plus si la variable est entre quotes, la liste des éléments avec @ prendra la forme de mots distincts, avec * d'un mot unique
for i in "${TB[@]}"; do echo "- ${i}"; done
- 1
- 2
- 3
- 4
- 5
for i in "${TB[*]}"; do echo "- ${i}"; done
- 1 2 3 4 5


 Altérer IFS pour stocker les éléments d'un texte dans un tableau
IP=10.20.30.40
oIFS="${IFS}"
IFS="."
set -A TB ${IP}
IFS="${oIFS}"
echo ${TB[2]}
30


 Arithmétique (entiers)

echo $((3*(2+1)))
9


 Sommer les éléments d'un tableau
oIFS="${IFS}"
IFS="+"
set -A TB 10 20 30 40 50
echo "Nous allons sommer ${TB[*]}"

Nous allons sommer 10+20+30+40+50
echo $(("${TB[*]}"))
150
IFS="${oIFS}"