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 Danswhile 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