Comment boucler sur les lignes dun fichier?

Dites que jai ce fichier:

hello world hello world 

Ce programme

#!/bin/bash for i in $(cat $1); do echo "tester: $i" done 

sorties

tester: hello tester: world tester: hello tester: world 

Je « voudrais avoir le for itérer sur chaque ligne individuellement en ignorant les espaces, cest-à-dire que les deux dernières lignes doivent être remplacées par

tester: hello world 

Utilisation de guillemets for i in "$(cat $1)"; entraîne laffectation du fichier entier à i en une seule fois. Que dois-je changer?

Réponse

(9 ans plus tard 🙂
Les deux réponses fournies échoueraient sur les fichiers sans nouvelle ligne à la fin, cela sautera effectivement la dernière ligne, ne produira aucune erreur, conduirait au désastre (appris dur manière :).

La meilleure solution concise que jai trouvée jusquà présent que « Just Works » (à la fois dans bash et sh):

while IFS="" read -r LINE || [ -n "${LINE}" ]; do echo "processing line: ${LINE}" done < /path/to/input/file.txt 

Pour une discussion plus approfondie, consultez cette discussion StackOverflow: Comment utiliser « while read « (Bash) pour lire la dernière ligne dun fichier sil ny a pas de nouvelle ligne à la fin du fichier?

Attention: cette approche ajoute une nouvelle ligne supplémentaire à la dernière ligne sil y a aucun déjà.

Commentaires

  • Belle prise, merci! Notez le " Attention que cela ajoute une nouvelle ligne supplémentaire à EOF sil ny en a pas déjà. " commentez cependant
  • Tobias, je ' Je vais ajouter ceci comme note, merci.

Réponse

Avec for et IFS :

#!/bin/bash IFS=$"\n" # make newlines the only separator set -f # disable globbing for i in $(cat < "$1"); do echo "tester: $i" done 

Notez cependant quil sautera les lignes vides car nouvelle ligne étant un caractère IFS-espace blanc, séquences de celui-ci compte pour 1 et les premiers et les derniers sont ignorés. Avec zsh et ksh93 (et non bash), vous pouvez le remplacer par IFS=$"\n\n" pour que le retour à la ligne ne soit pas traité spécialement, mais notez que tous les caractères de retour à la ligne fin (y compris les lignes vides de fin) seront toujours supprimés par la substitution de commande.

Ou avec read (plus de cat ):

#!/bin/bash while IFS= read -r line; do echo "tester: $line" done < "$1" 

Là, les lignes vides sont conservées, mais notez que cela sauterait la dernière ligne si elle nétait pas correctement délimitée par un caractère de nouvelle ligne.

Commentaires

  • merci, je ne ' pas savoir que lon pourrait < en une boucle entière. Bien que cela soit parfaitement logique maintenant, je lai vu
  • Je vois IFS \ read -r line' in second example. Is really IFS = `nécessaire? À mon humble avis, il suffit de dire: while read -r line; do echo "tester: $line"; done < "$1"
  • @GrzegorzWierzowiecki IFS= désactive la suppression des espaces blancs de début et de fin. Voir Dans while IFS= read.., pourquoi IFS na-t-il aucun effet?
  • @BenMares Pour empêcher le globbing expressions apparaissant éventuellement dans le texte que nous lisons depuis leur extension vers des noms de fichiers correspondants. Essayez, par exemple, printf '%s\n' '*o' 'bar' >afile; touch foo; IFS=$'\n'; for i in $(cat afile); do echo "$i"; done.
  • Un while IFS= read -r line || [ "$line" ]; do traitera une ligne de fin qui nest pas correctement délimitée par un caractère de nouvelle ligne (mais il sera rajouté).

Réponse

Pour ce que ça vaut, je dois faire cela assez souvent, et je ne me souviens jamais de la manière exacte dutiliser while IFS= read..., jai donc défini la fonction suivante dans mon profil bash:

# iterate the line of a file and call input function iterlines() { (( $# < 2 )) && { echo "Usage: iterlines <File> <Callback>"; return; } local File=$1 local Func=$2 n=$(cat "$File" | wc -l) for (( i=1; i<=n; i++ )); do "$Func" "$(sed "${i}q;d" "$File")" done } 

Cette fonction détermine dabord le nombre de lignes dans le fichier, puis utilise sed pour extraire ligne après ligne, et passe chaque ligne comme un argument de chaîne unique à nimporte quel fonction. Je suppose que cela peut devenir vraiment inefficace avec des fichiers volumineux, mais cela na pas été un problème pour moi jusquà présent (suggestions sur la façon daméliorer cet accueil bien sûr).

Lutilisation est assez douce IMO:

>> cat example.txt # note the use of spaces, whitespace, etc. a/path This is a sentence. "wi\th quotes" $End >> iterlines example.txt echo # preserves quotes, $ and whitespace a/path This is a sentence. "wi\th quotes" $End >> x() { echo "$#"; }; iterlines example.txt x # line always passed as single input string 1 1 1 1 1 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *