J'utilise généralement la commande read pour lire ligne par ligne un fichier d'entrée dans le script Shell. Un exemple de code, tel que celui ci-dessous, donne un résultat incorrect si aucune nouvelle ligne n'est insérée à la fin de la dernière ligne du fichier d'entrée, blah.txt.
#!/bin/sh
while read line
do
echo $line
done <blah.txt
Donc, si le fichier d’entrée lit quelque chose comme:
One
Two
Three
Four
et je ne frappe pas retour après quatre, le script ne parvient pas à lire la dernière ligne, et imprime
One
Two
Three
Maintenant, si je laisse une ligne vierge supplémentaire après quatre, comme,
One
Two
Three
Four
//blank line
la sortie imprime toutes les lignes, y compris Quatre. Cependant, ce n'est pas le cas lorsque je lis une ligne à l'aide de la commande cat
; toutes les lignes, y compris la dernière, sont imprimées sans que je doive ajouter une ligne vierge supplémentaire à la fin.
Quelqu'un a des idées sur pourquoi cela se produit? Les scripts que je crée seront principalement exécutés par d'autres. Il n'est donc pas nécessaire qu'ils ajoutent une ligne vierge supplémentaire à la fin de chaque fichier d'entrée.
J'essaie de comprendre cela depuis des siècles. Je vous en serais reconnaissant si vous aviez des solutions (bien sûr, la commande cat
en est une, mais j'aimerais connaître la raison de cette lecture qui ne fonctionne pas aussi bien).
read
lit jusqu'à ce qu'il trouve un caractère de nouvelle ligne ou la fin du fichier et renvoie un code de sortie différent de zéro s'il rencontre une fin de fichier. Il est donc tout à fait possible qu'il lise une ligne et renvoie un code de sortie non nul.
Par conséquent, le code suivant n'est pas sûr si l'entrée peut ne pas être terminée par une nouvelle ligne:
while read LINE; do
# do something with LINE
done
parce que le corps de la while
ne sera pas exécuté sur la dernière ligne.
Techniquement, un fichier ne se terminant pas par une nouvelle ligne n'est pas un fichier texte et les outils texte peuvent échouer de manière étrange sur un tel fichier. Cependant, je suis toujours réticent à me rabattre sur cette explication.
Une façon de résoudre le problème est de vérifier si ce qui a été lu est non vide (-n
):
while read -r LINE || [[ -n $LINE ]]; do
# do something with LINE
done
Parmi les autres solutions, utilisez mapfile
pour lire le fichier dans un tableau, le transférer à travers un utilitaire dont la garantie est de terminer correctement la dernière ligne (grep .
, par exemple, si vous ne voulez pas utiliser de lignes vides), traitement itératif avec un outil comme awk
(ce qui est généralement ma préférence).
Notez que -r
est presque certainement nécessaire dans la variable read
; read
ne réinterprète pas \
- dans l'entrée.
DONE=false
until $DONE
do
read line || DONE=true
echo $line
done < blah.txt
Réponse en ligne:
IFS=$'\n'; for line in $(cat file.txt); do echo "$line" ; done
Utilisez la boucle while comme ceci:
while IFS= read -r line || [ -n "$line" ]; do
echo "$line"
done <file
Ou en utilisant grep
avec la boucle while:
while IFS= read -r line; do
echo "$line"
done < <(grep "" file)
Utiliser grep .
au lieu de grep ""
sautera les lignes vides.
Remarque:
L'utilisation de IFS=
conserve l'indentation de ligne intacte.
Vous devriez presque toujours utiliser l'option -r avec read.
Un fichier sans nouvelle ligne à la fin n'est pas un fichier texte unix standard.
Le code ci-dessous avec la boucle "En lecture" redirigée me convient
while read LINE
do
let count++
echo "$count $LINE"
done < $FILENAME
echo -e "\nTotal $count Lines read"