Le langage bash propose l‘utilisation de tableaux (array). Cela permet un traitement itératif. Bien souvent, lorsqu'on script en bash on oublie cette fonctionnalité. Petit rappel.
$ Array=(item1 item2 item3 "liste d'items")
$ echo ${Array[0]}
item1
$ echo ${Array[2]}
item3
i=3
$ echo ${Array[$i]}
liste d'items
Le premier élément du tableau a pour index 0.
echo ${#Array[@]}
4
$ echo ${Array[*]}
item1 item2 item3 liste d'items
for i in ${Array[*]}
do
echo $i
done
item1
item2
item3
liste
d'items
Cette manière de faire ne donne pas forcément le résultat escompté. L'indice 4 qui contient un blanc n'est pas restitué comme on pourrait le penser.
C'est avec la manière globale la plus sur façon de faire.
$ for (( i=0; i<${#Array[@]}; i++ )); do
echo "n° $i : ${Array[$i]}"
done
n° 0 : item1
n° 1 : item2
n° 2 : item3
n° 3 : liste d'items
Bash a une variable interne $IFS, comme awk qui détermine la césure des mots.
Il faut faire attention à son contenu. Cela peut avoir une influence sur la gestion des noms d‘éléments dans une array.
Ne pas hésiter à regarder et àchanger sa valeur.
IFS='' correspond au blanc comme séparateur.
Par exemple, si on veut utiliser la virgule comme séparateur:
$ IFS=','
arr_nombres=(12,34,56)
$ echo ${arr_nombres[*]}
12 34 56
$ IFS=''
$ Array+=(item5)
jlb@mignon:~$ echo ${Array[*]}
item1 item2 item3 liste d'items item5
$ unset Array
$ echo ${Array[*]}
La ligne blanche confirme que le tableau a été supprimé.
C'est la solution à laquelle on pense en premier. On parcourt le tableau et on teste chaque élément du tableau pour voir si il correspond à la valeur.
Il vaut mieux écrire un script. Par exemple in array.bash.
#!/bin/bash
function array_contains()
{
local n=$#
local value=${!n}
for ((i=1;i < $#;i++)) {
if [ "${!i}" == "${value}" ]; then
echo "true"
return 0
fi
}
echo "false"
return 1
}
lang=(awk c html makefile perltk python tk bash dialog js perl php tcl tkinter)
for j in "awk" "ada" "python" "lisp"
do
if [ $(array_contains "${lang[@]}" "$j") == "true" ]; then
echo $j
fi
done
$ ./array.bash awk python
Cela fonctionne mais ce n'est pas la solution la plus optimsée.
La solution élégante consiste à utiliser l'opérateur *=~ dans le tableau.
La syntaxe est de typr
if [[ " ${lang[@]} " =~ " ${j} " ]];
$ lang=(awk c html makefile perltk python tk bash dialog js perl php tcl tkinter)
for j in ada python lisp modula bash c c++
do
if [[ " ${lang[@]} " =~ " $j " ]]; then
echo $j
fi
done
python
bash
c
a1=(chien chat canari)
$ a2=(lapin hamster souris)
$ a=("${a1[@]}" "${a2[@]}")
$ for i in "${a[@]}" ; do echo "$i" ; done
chien
chat
canari
lapin
hamster
souris
Pour un tri numérique on utilise sort -n pour les nombres et sort pour les chaines.
$ nombres=(5 23 1 12 12)
$ trie=($(printf "%s\n" ${nombres[*]} | sort -n)
$ echo ${trie[*]}
1 5 12 12 23
Les autres options sont possibles comme -rn pour reverse numérique, -r pour reverse, -h pour une vision "humaine" des tailles de disques et de fichiers, -u pour unique, -V pour trier par version.
Vous pouvez consulter le man de sort pour plus de possibilité.
$ nombres=(5 23 1 12 12)
$ trie=($(printf "%s\n" ${nombres[*]} | sort -r)
$ echo ${trie[*]}
23 12 12 5 1
sorted=($(printf "%s\n" ${nums[*]} | sort -r))
$ echo ${sorted[*]}
5 23 12 12 1
$ disk_size=($(df | awk '{print $4}' | sort -h))
$ echo ${disk_size[*]}
Taille 5,0M 784M 785M 3,8G 3,9G 6,2G 8,1G 186G
On voit très dans l'exemple avec sort - que l'ordre correspond à l'ordre alphabetique et non l'ordre numérique.
On peut ausi utiliser IFS comme délimiteur.
$ rray=(item val list string)
$ IFS=$'\n' sorted=($(sort <<<"${array[*]}")); unset IFS
$ printf "[%s]\n" "${sorted[@]}"
Voici un exemple de script avec le très connu buble sort en utilisant une variable globale BSORT, bubble.bash .
declare BSORT=()
function bubble_sort()
{ #
# @param [ARGUMENTS]...
#
# Sort all positional arguments and store them in global array BSORT.
# Without arguments sort this array. Return the number of iterations made.
#
# Bubble sorting lets the heaviest element sink to the bottom.
#
(($# > 0)) && BSORT=("$@")
local j=0 ubound=$((${#BSORT[*]} - 1))
while ((ubound > 0))
do
local i=0
while ((i < ubound))
do
if [ "${BSORT[$i]}" \> "${BSORT[$((i + 1))]}" ]
then
local t="${BSORT[$i]}"
BSORT[$i]="${BSORT[$((i + 1))]}"
BSORT[$((i + 1))]="$t"
fi
((++i))
done
((++j))
((--ubound))
done
}
bubble_sort chat chien canari lapin souris
echo ${BSORT[@]}
/bubble.bash canari chat chien lapin souris