En parcourant le contenu d'un fichier dans Bash
Comment itérer sur chaque ligne d'un fichier texte avec Bash?
Avec ce script:
echo "Start!"
for p in (peptides.txt)
do
echo "${p}"
done
- Je obtenir ce résultat à l'écran:
Start!
./runPep.sh: line 3: syntax error near unexpected token `('
./runPep.sh: line 3: `for p in (peptides.txt)'
(Plus tard, je veux faire quelque chose de plus compliqué avec $p
que juste la sortie à l'écran.)
La variable d'environnement SHELL est (à partir de env):
SHELL=/bin/bash
/bin/bash --version
de sortie:
GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
cat /proc/version
de sortie:
Linux version 2.6.18.2-34-default (geeko@buildhost) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006
Le fichier peptides.txt contient:
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL
- Oh, je vois beaucoup de choses se sont passées ici: tous les commentaires ont été supprimés et la question d'être rouvert. Juste pour la référence, de la accepté de répondre à Lire un fichier ligne par ligne de l'affectation de la valeur à une variable aborde le problème d'une manière canonique et doit être préférée à la accepté ici.
Vous devez vous connecter pour publier un commentaire.
Une façon de le faire est:
Comme l'a souligné dans les commentaires, ce qui a pour effets secondaires de la coupe de leader d'espaces, de l'interprétation de la barre oblique inverse des séquences, et le saut de la dernière ligne si il manque une terminaison de fin de ligne. Si ce sont des questions, vous pouvez le faire:
Exceptionnellement, si la corps de boucle peut lire l'entrée standard, vous pouvez ouvrir le fichier en utilisant un autre descripteur de fichier:
Ici, 10 est juste un nombre arbitraire (différente de 0, 1, 2).
cat
mais remplacercat
partac
.while read p || [[ -n $p ]]; do ...
n
après la barre oblique inverse, et les lignes se concaténées. Parce que ça voudrait dire, les séquences d'échappement barre oblique inverse de\n
, l'amenant à être interprété littéralement, plutôt que comme un retour à la ligne. Mais le fait que la barre oblique inverse disparaît, ainsi que le saut de ligne, signifie qu'il est consommé pour quelque sorte de s'en échapper, comme prévu, mais est fusionné avec l'original du caractère de saut de ligne dans quelque chose qui n'est pas imprimé... avez-vous un outil qui affiche non imprimés en caractères d'une certaine façon? M'intéresse ce que les résultats.a\na\n\\n
ressemblera:610a 610a 5c0a
(0a hex est de 10, de sorte \n). Si le dernier cas, le "5c" ou de la "\" est échapper à un seul caractère.\n
est un seul et même personnage. Pour quelque raison, j'ai pensé qu'il obtient backresolved à la séquence de contrôle au cours de leur traitement. Pourtant, c'est un peu bizarre qu'un échappé\n
est une chose sans une représentation imprimée. On s'attend à résoudre pour le char de la séquence "\n" quand échappé.-r
drapeau n'?IFS
désactive queread
divise la ligne dans les champs. Et parce queread
échoue lors de la rencontre de fin de fichier avant la ligne se termine, nous testons également pour une ligne non vide.read
est ignorant la\r
personnage lorsque le fichier utilise windows fins de ligne (c'est à dire\r\n
). Comment puis-je faireread
traiter\r
dans le cadre de la séquence de saut de ligne?et le one-liner variante:
Ces options pour ignorer la dernière ligne du fichier si il n'y a pas de fuite de saut de ligne.
Vous pouvez éviter cela par ce qui suit:
if grep -q 'findme' <<< "$var"
) mais pas de portable, et je ne veux pas commencer un grand pipeline avec un. Quelque chose commecat ifconfig.output | grep inet[^6] | grep -v '127.0.0.1' | awk '{print $2}' | cut -d':' -f2
est plus facile à lire, puisque tout ce qui suit de gauche à droite. C'est comme strtoking avecawk
au lieu decut
parce que vous ne voulez pas vide jetons - c'est en quelque sorte un abus de la commande, mais c'est juste la façon dont c'est fait.< peptides.txt | while read line...
read -r
dans certains cas particuliers. Fondamentalement, toujours utiliserread -r
sauf si vous nécessitent l'étrange comportement de la plaine de l'héritageread
.Option 1a: boucle While: une Seule ligne à la fois: la redirection d'Entrée
Option 1b: boucle While: une Seule ligne à la fois:
Ouvrir le fichier, lire à partir d'un descripteur de fichier (dans ce cas, le descripteur de fichier n ° 4).
done < $filename
avecdone 4<$filename
(ce qui est utile si vous voulez lire le nom de fichier à partir d'un paramètre de la commande, dans ce cas, vous pouvez remplacer$filename
par$1
).tail -n +2 myfile.txt | grep 'somepattern' | cut -f3
, lors de l'exécution de commandes ssh à l'intérieur de la boucle (consomme stdin); l'option 2 semble être le seul moyen?Ce n'est pas mieux que les autres réponses, mais est un moyen de plus pour obtenir le travail fait dans un fichier sans espaces (voir les commentaires). Je trouve que j'ai souvent besoin d'un chemises de creuser par le biais de listes dans des fichiers texte sans l'étape supplémentaire de l'utilisation de séparer les fichiers de script.
Ce format me permet de mettre tout cela en une seule ligne de commande. Changer le "echo $mot" partie de ce que vous voulez et vous pouvez effectuer plusieurs commandes séparées par des points-virgules. L'exemple suivant utilise le contenu du fichier comme arguments dans les deux autres scripts que vous pouvez avoir écrit.
Ou si vous avez l'intention de l'utiliser comme un éditeur de flux (en savoir sed), vous pouvez faire un dump de la sortie vers un autre fichier comme suit.
Je les ai utilisées comme écrit ci-dessus, car j'ai utilisé des fichiers texte où j'ai créé avec un mot par ligne. (Voir les commentaires) Si vous avez des espaces que vous ne voulez pas partager votre mots/lignes, il devient un peu plus laide, mais la même commande fonctionne toujours comme suit:
Cela indique au shell à se diviser sur les retours à la ligne uniquement, pas d'espaces, puis revient de l'environnement à ce qu'il était auparavant. À ce stade, vous pourriez envisager de les mettre dans un script shell plutôt que de presser tout en une seule ligne, bien que.
Bonne chance!
for
rend l'entrée des jetons/lignes soumises à la coquille d'expansion, qui est généralement indésirable; essayez ceci:for l in $(echo '* b c'); do echo "[$l]"; done
- comme vous le verrez, la*
- même si à l'origine d'un cité littérale - se développe à la fichiers dans le répertoire courant."$word"
et"$line"
...for
pour itérer lignes du fichier est une mauvaise idée. De Plus, l'expansion aspect évoqué par @mklement0 (même si ça peut probablement être contournée par la mise en échappé citations, ce qui rend les choses plus complexe et moins lisible).Un peu plus de choses qui ne sont pas couverts par d'autres réponses:
Lecture à partir d'un fichier délimité par des
De lecture à partir de la sortie d'une autre commande, à l'aide de processus de substitution
Cette approche est mieux que
command ... | while read -r line; do ...
parce que la boucle while ici s'exécute dans le shell courant plutôt qu'un shell interne est exécuté comme dans le cas de la seconde. Voir le post Une variable modifiée à l'intérieur d'une boucle while n'est pas de rappeler.Lecture à partir d'un null délimité d'entrée, par exemple
find ... -print0
Liés à lire: BashFAQ/020 - Comment puis-je trouver et de gérer en toute sécurité les noms de fichier contenant des sauts de ligne, les espaces ou les deux?
La lecture de plus d'un fichier à un moment
Basé sur @chepner de l' réponse ici:
-u
est un bash extension. Pour la compatibilité POSIX, chaque appel ressemblerait à quelque chose commeread -r X <&3
.Lire tout un fichier dans un tableau (Bash versions antérieures à 4)
Si le fichier se termine par une incomplète de ligne (newline manquant à la fin), puis:
Lire tout un fichier dans un tableau (Bash versions 4x et plus tard)
ou
Et puis
Plus sur le shell les builtins
lire
etreadarray
commandes - GNUPlus sur
FI
- WikipédiaRelated posts:
command < input_filename.txt
vous pouvez toujours faireinput_generating_command | command
oucommand < <(input_generating_command)
Utiliser une boucle while, comme ceci:
Notes:
Si vous ne définissez pas la
IFS
correctement, vous perdrez de l'indentation.Vous devriez toujours utiliser l'option-r à lire.
Ne lisez pas les lignes avec
for
-r
option?Note #2
est un lien où il est décrit en détail...-u
option, vous parlez d'un autre exemple avec-u
?Si vous ne voulez pas que votre lecture pour être rompu par un caractère de saut de ligne, utilisez -
Puis exécutez le script avec un nom de fichier en paramètre.
Supposons que vous avez ce fichier:
Il y a quatre éléments qui permettront de modifier le sens de la sortie du fichier lu par de nombreux Bash solutions:
Si vous souhaitez que le fichier texte ligne par ligne, y compris les lignes vides et la terminaison des lignes sans CR, vous devez utiliser une boucle while et vous devez avoir un autre test pour la dernière ligne.
Ici sont les méthodes qui peuvent modifier le fichier (en comparaison de ce que
cat
retours):1) Perdre la dernière ligne et d'attaque et de fuite des espaces:
(Si vous ne
while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
au lieu de cela, vous préserver de l'attaque et de fuite des espaces, mais encore de perdre la dernière ligne si il n'est pas résilié avec CR)2) à l'Aide de processus de substitution avec
cat
va se lit tout le fichier en un clin d'oeil et perd le sens de la ligne:(Si vous supprimez le
"
de$(cat /tmp/test.txt)
de le lire mot par mot plutôt qu'un trait. Probablement pas ce qui est prévu...)Le plus robuste et le plus simple pour lire un fichier ligne par ligne, et de préserver tous les espacement est:
Si vous voulez bande de diriger et d'espaces commerciaux, de supprimer la
IFS=
partie:(Un fichier texte sans une terminaison de
\n
, assez commun, est considéré comme rompu sous POSIX. Si vous pouvez compter sur la fuite\n
vous n'avez pas besoin|| [[ -n $line ]]
dans lewhile
boucle.)Plus à la BASH FAQ
Voici ma vraie vie exemple comment faire une boucle lignes d'un autre programme de la sortie, vérifier pour les sous-chaînes, baisse des guillemets à partir d'une variable, utilisez cette variable à l'extérieur de la boucle. Je suppose que beaucoup de se poser ces questions, tôt ou tard.
Déclarer la variable en dehors de la boucle, la valeur de consigne et de l'utiliser à l'extérieur de la boucle nécessite fait <<< "$(...)" de la syntaxe. Application doivent être exécutés dans un contexte de console actuelle. Des guillemets autour de la garde des retours à la ligne de flux de sortie.
Boucle de match pour les sous-chaînes lit ensuite nom=valeur paire, les criques du côté droit de la partie de la dernière = caractère, gouttes pour la première fois, les gouttes de la dernière citation, nous avons une propre valeur pour être utilisées ailleurs.
Et c'est plutôt très en retard, mais avec la pensée que cela peut aider quelqu'un, je suis l'ajout de la réponse. Aussi cela peut ne pas être le meilleur moyen.
head
commande peut être utilisée avec-n
argument de lire n lignes à partir du début du fichier et de la même manièretail
commande peut être utilisée pour lire à partir du bas. Maintenant, pour aller chercher de nième ligne à partir d'un fichier, nous nous dirigeons n lignes, pipe les données de la queue seulement 1 ligne de canalisations de données.@Pierre: Ce pourrait travailler pour vous-
Ce serait de retour la sortie-
*
, et d'un énorme trésor de la facturation-sauvegardes de données a été perdu.