Le problème n'est pas dans cat
, ni dans le for
boucle en soi ; c'est dans l'utilisation des guillemets. Lorsque vous écrivez soit :
for i in `cat file`
ou (mieux):
for i in $(cat file)
ou (en bash
):
for i in $(<file)
le shell exécute la commande et capture la sortie sous forme de chaîne, en séparant les mots au niveau des caractères dans $IFS
. Si vous voulez que les lignes entrent dans $i
, vous devez soit jouer avec IFS
ou utilisez le while
boucle. Le while
loop est préférable s'il existe un risque que les fichiers traités soient volumineux ; il n'est pas nécessaire de lire tout le fichier en mémoire en une seule fois, contrairement aux versions utilisant $(...)
.
IFS='
'
for i in $(<file)
do echo "$i"
done
Les guillemets autour du "$i"
sont généralement une bonne idée. Dans ce contexte, avec le $IFS
modifié , ce n'est en fait pas critique, mais les bonnes habitudes sont quand même de bonnes habitudes. Cela compte dans le script suivant :
old="$IFS"
IFS='
'
for i in $(<file)
do
(
IFS="$old"
echo "$i"
)
done
lorsque le fichier de données contient plusieurs espaces entre les mots :
$ cat file
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
Sortie :
$ sh bq.sh
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
Sans les guillemets :
$ cat bq.sh
old="$IFS"
IFS='
'
for i in $(<file)
do
(
IFS="$old"
echo $i
)
done
$ sh bq.sh
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
Vous pouvez utiliser IFS
variable pour spécifier que vous voulez une nouvelle ligne comme séparateur de champ :
IFS=$'\n'
for i in `cat file`
do
echo $i
done
la boucle for couplée à un changement du séparateur de champ interne (IFS) lira le fichier comme prévu
pour une entrée
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
Boucle For couplée à un changement d'IFS
old_IFS=$IFS
IFS=$'\n'
for i in `cat file`
do
echo $i
done
IFS=$old_IFS
résultats en
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma