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}"

6 février 2018

Bugs Oracle 12c - impacts sur HR Access

Les premières versions Oracle 12c (au moins jusqu'à la 12.1.0.2) souffrent d’un nombre important de bugs . Ces bugs peuvent altérer les performances mais aussi impacter les résultats retournés par les ordres SQL de façon aléatoire entraînant un risque important sur la validité des données.

Gabriel en a fait l'expérience lors de générations ... Il s'est rendu compte que les recherches à la liste des macros HR ne fonctionnait pas bien :

SQL> SELECT A.CDPREA,B.CDSTDO,B.CDINFO,A.NUPROE
FROM  AP35 A,AP30 B,AP20 C
WHERE  A.CDPROS  = 'AOODS'
AND    B.CDPROS  = A.CDPREA
AND    C.CDPROS  = A.CDPREA
AND    B.CDPROS  = C.CDPROS
AND    C.CDSTD2  = B.CDSTDO
ORDER BY CDPREA,CDSTDO,CDINFO
/
no rows selected


Mais en retirant le parallélisme de Oracle

SQL> alter session disable parallel query;
SQL> SELECT A.CDPREA,B.CDSTDO,B.CDINFO,A.NUPROE
FROM  AP35 A,AP30 B,AP20 C
WHERE  A.CDPROS  = 'AOODS'
AND    B.CDPROS  = A.CDPREA
AND    C.CDPROS  = A.CDPREA
AND    B.CDPROS  = C.CDPROS
AND    C.CDSTD2  = B.CDSTDO
ORDER BY CDPREA,CDSTDO,CDINFO

CDPRE CD CD NU
----- -- -- --
AO0DP OY Y1 02
AO0DP OY Y2 02
AO0DP OY Y3 02
AO0DP OY Y4 02
AO0DP OY Y5 02

...

Exemple de bugs Oracle (liste non exhaustive) :
  • Bug 23147905  Wrong Results with filtering on an aggregation expression
  • Wrong Results for a Query When "_ROWSETS_ENABLED" = TRUE (Doc ID 2079913.1)
  • Bug 20634449  Wrong results from OUTER JOIN with a bind variable and a GROUP BY clause in 12.1.0.2

Voyez avec le DBA à installer les Patch Set Update Oracle ... !

cf article du 22/08/2017 sur le site de la HotLine "Problème aléatoire Oracle version 12.1.0.2.0 sur les résultats retournés par certains ordres SQL" :
"Les clients concernés doivent donc appliquer le dernier « Patch Set Update » (actuellement en date de juillet 2017) disponible sur le site support d’Oracle dans la rubrique « Recommended Patch Advisor »."