J'ai un fichier texte qui contient quelque chose comme ceci:
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
J'ai écrit un script
for i in `cat file`
do
echo $i
done
Pour une raison quelconque, la sortie du script ne produit pas le fichier ligne par ligne mais le rompt au niveau des virgules, ainsi que de la nouvelle ligne. Pourquoi est chat ou "pour bla dans cat xyz
"faire cela et comment puis-je faire en sorte de ne PAS le faire? Je sais que je peux utiliser un
while read line
do
blah balh blah
done < file
mais je veux savoir pourquoi cat ou le "for blah in" fait cela pour approfondir ma compréhension des commandes unix. La page de manuel de Cat ne m'a pas aidé et la recherche ou la boucle dans le manuel bash n'a donné aucune réponse ( http://www.gnu.org/software/bash/manual/bashref.html =). Merci d'avance pour votre aide.
Le problème n'est pas dans cat
, ni dans la boucle for
en soi; c'est dans l'utilisation de guillemets. Lorsque vous écrivez:
for i in `cat file`
ou mieux):
for i in $(cat file)
ou (dans 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 soient saisies dans $i
, Vous devez soit jouer avec IFS
, soit utiliser la boucle while
. La boucle while
est meilleure s'il existe un danger que les fichiers traités soient volumineux; il n'a pas à lire tout le fichier en mémoire d'un coup, 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
$
Production:
$ sh bq.sh
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
Sans les guillemets doubles:
$ 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 la variable IFS
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
Pour boucle couplée à un changement IFS
old_IFS=$IFS
IFS=$'\n'
for i in `cat file`
do
echo $i
done
IFS=$old_IFS
résulte en
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
IFS - Le séparateur de champ interne peut être réglé pour obtenir ce que vous voulez.
Pour lire une ligne entière à la fois, utilisez: IFS = ""
cat filename | while read i
do
echo $i
done