Traiter des listes correctement en Bash
Bien souvent j'utilise des fonctions de boucle en Bash pour traiter des fichiers ou faire des tests. Vous pouvez utiliser une liste que vous donnez manuellement, une liste de fichier ou carrément utiliser une commande qui génère la liste.
Restons dans la simplicité, voici un ou deux exemples:
# for i in "foo bar baz"
do
echo $i
done
> affiche:
# foo
# bar
# baz
#for i in `find ./ -name "*.php"`
do
cp $i ~/sauvegarde_php
sed -i "s/\r//g" $i
done
> copie chaque fichier php dans un répertoire de sauvegarde
> puis remplace "\r" dans chaque fichier trouvé
#for i in `cat monfichier.txt`
do
grep $i autrefichier.txt || echo "$i not found !"
done
> à chaque ligne trouvé dans monfichier.txt
> je vérifie si elle existe aussi dans autrefichier.txt
> sinon j'affiche le souci
Là où on peut avoir un souci, c'est justement dans le dernier exemple. Imaginons que monfichier.txt contienne:
foo
bar
baz
et le script:
#for i in `cat monfichier.txt`
do
echo $i
done
Dans ce cas, on retrouve bien une ligne pour chaque élément.
Mais un problème intervient dans ce cas:
une ligne à chercher
une autre ligne
la dernière ligne
Le résultat va être:
une
ligne
à
chercher
une
autre
ligne
la
dernière
ligne
Stupeur... tremblements... ce n'est pas une erreur mais le fonctionnement normal du principe de liste en Bash. En effet, la séparation des éléments se fait via des retours chariots ou des espaces...
Voici comment vous pouvez vous en sortir: utiliser la commande "read" qui attend bien un retour chariot (ou n) pour passer à la suite:
cat monfichier.txt | while read i
do
echo $i
done
Et on retrouve notre liste sans coupure à chaque espace mais bien pour chaque ligne.
Efficace non ?
Trackbacks
Pour ajouter un trackback (retrolien) sur ce ticket, utilisez cette adresse: http://www.metal3d.org/index.php/trackback/default/tb?id=blog%2F184

Argh ! Un pipe ! Quel horreur.
Je propose plutôt :
while read ligne;
do
echo $ligne
done < monfichier.txt
C'est plus joli, non ?
Sinon, on peut aussi jouer en modifiant IFS, mais c'est moins portable...