Comment parcourir chaque ligne d'un fichier texte avec Bash ?
Avec ce script:
echo "Start!"
for p in (peptides.txt)
do
echo "${p}"
done
J'obtiens cette sortie sur 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é $p
que de simplement afficher sur l'écran.)
La variable d'environnement SHELL est (de env):
SHELL=/bin/bash
/bin/bash --version
production:
GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
cat /proc/version
production:
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
Réponses:
Une façon de le faire est:
Comme indiqué dans les commentaires, cela a les effets secondaires de rogner les espaces blancs de tête, d'interpréter les séquences de barre oblique inverse et de sauter la dernière ligne s'il manque un saut de ligne de fin. Si ce sont des préoccupations, vous pouvez faire:
Exceptionnellement, si le corps de la boucle peut lire à partir de l'entrée standard , vous pouvez ouvrir le fichier à l'aide d'un descripteur de fichier différent:
Ici, 10 n'est qu'un nombre arbitraire (différent de 0, 1, 2).
la source
while read p || [[ -n $p ]]; do ...
et la variante monoligne:
Ces options ignoreront la dernière ligne du fichier s'il n'y a pas de saut de ligne de fin.
Vous pouvez éviter cela en procédant comme suit:
la source
Option 1a: Pendant la boucle: Une seule ligne à la fois: Redirection d'entrée
Option 1b: Pendant la boucle: Une seule ligne à la fois:
Ouvrez le fichier, lisez à partir d'un descripteur de fichier (dans ce cas, le descripteur de fichier # 4).
la source
done < $filename
pardone 4<$filename
(ce qui est utile si vous souhaitez lire le nom de fichier à partir d'un paramètre de commande, auquel cas vous pouvez simplement le remplacer$filename
par$1
).tail -n +2 myfile.txt | grep 'somepattern' | cut -f3
, lors de l'exécution des commandes ssh à l'intérieur de la boucle (consomme stdin); l'option 2 ici semble être la seule façon?Ce n'est pas mieux que les autres réponses, mais c'est une autre façon de faire le travail dans un fichier sans espaces (voir commentaires). Je trouve que j'ai souvent besoin de lignes simples pour fouiller les listes dans les fichiers texte sans l'étape supplémentaire d'utiliser des fichiers de script séparés.
Ce format me permet de tout mettre en une seule ligne de commande. Changez la portion "echo $ word" en ce que vous voulez et vous pouvez émettre plusieurs commandes séparées par des points-virgules. L'exemple suivant utilise le contenu du fichier comme arguments dans deux autres scripts que vous avez peut-être écrits.
Ou si vous avez l'intention de l'utiliser comme un éditeur de flux (learn sed), vous pouvez vider la sortie dans un autre fichier comme suit.
Je les ai utilisés comme écrit ci-dessus parce que j'ai utilisé des fichiers texte où je les ai créés avec un mot par ligne. (Voir les commentaires) Si vous avez des espaces que vous ne voulez pas séparer vos mots / lignes, cela devient un peu plus laid, mais la même commande fonctionne toujours comme suit:
Cela indique simplement au shell de se diviser uniquement sur les nouvelles lignes, pas sur les espaces, puis ramène l'environnement à ce qu'il était auparavant. À ce stade, vous voudrez peut-être envisager de tout mettre dans un script shell plutôt que de le regrouper sur une seule ligne.
Bonne chance!
la source
for
rend les jetons / lignes d'entrée sujets à des extensions de shell, ce qui n'est généralement pas souhaitable; essayez ceci:for l in $(echo '* b c'); do echo "[$l]"; done
- comme vous le verrez, le*
- même si à l'origine un littéral cité - se développe dans les fichiers du répertoire courant.for
pour itérer les lignes de fichiers est une mauvaise idée. De plus, l'aspect d'expansion mentionné par @ mklement0 (même si cela peut probablement être contourné en introduisant des guillemets échappés, ce qui rend les choses plus complexes et moins lisibles).Quelques autres choses non couvertes par d'autres réponses:
Lecture à partir d'un fichier délimité
Lecture à partir de la sortie d'une autre commande, en utilisant la substitution de processus
Cette approche est meilleure que
command ... | while read -r line; do ...
parce que la boucle while s'exécute ici dans le shell actuel plutôt que dans un sous-shell comme dans le cas de ce dernier. Voir le post associé Une variable modifiée à l'intérieur d'une boucle while n'est pas mémorisée .Lecture à partir d'une entrée délimitée par des valeurs nulles, par exemple
find ... -print0
Lecture connexe: BashFAQ / 020 - Comment puis-je trouver et gérer en toute sécurité les noms de fichiers contenant des sauts de ligne, des espaces ou les deux?
Lecture à partir de plusieurs fichiers à la fois
Basé sur la réponse de @ chepner ici :
-u
est une extension bash. Pour la compatibilité POSIX, chaque appel ressemblerait à quelque chose commeread -r X <&3
.Lecture d'un fichier entier dans un tableau (versions Bash antérieures à 4)
Si le fichier se termine par une ligne incomplète (saut de ligne manquant à la fin), alors:
Lecture d'un fichier entier dans un tableau (versions Bash 4x et ultérieures)
ou
Et alors
En savoir plus sur les commandes
read
et lesreadarray
commandes internes du shell - GNUEn savoir plus sur
IFS
- WikipediaArticles Similaires:
la source
command < input_filename.txt
vous pouvez toujours faireinput_generating_command | command
oucommand < <(input_generating_command)
Utilisez une boucle while, comme ceci:
Remarques:
Si vous ne définissez pas
IFS
correctement, vous perdrez l'indentation.Vous devriez presque toujours utiliser l'option -r avec read.
Ne lisez pas les lignes avec
for
la source
-r
option?Note #2
est un lien où il est décrit en détail ...-u
option, parlez-vous d'un autre exemple avec-u
?Supposons que vous ayez ce fichier:
Il existe quatre éléments qui modifieront la signification de la sortie de fichier lue par de nombreuses solutions Bash:
Si vous souhaitez que le fichier texte ligne par ligne, y compris les lignes vides et les lignes de terminaison sans CR, vous devez utiliser une boucle while et vous devez avoir un test alternatif pour la ligne finale.
Voici les méthodes qui peuvent changer le fichier (par rapport à ce qui
cat
retourne):1) Perdez la dernière ligne et les espaces de début et de fin:
(Si vous le faites à la
while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
place, vous conservez les espaces de début et de fin mais perdez toujours la dernière ligne si elle ne se termine pas par CR)2) L'utilisation de la substitution de processus avec
cat
will lit le fichier entier en une seule gorgée et perd la signification des lignes individuelles:(Si vous enlevez le
"
de$(cat /tmp/test.txt)
vous lisez le fichier mot par mot plutôt qu'une gorgée. Aussi probablement pas ce qui est prévu ...)La façon la plus robuste et la plus simple de lire un fichier ligne par ligne et de conserver tout l'espacement est:
Si vous souhaitez supprimer les espaces de tête et d'échange, supprimez la
IFS=
pièce:(Un fichier texte sans terminaison
\n
, si vous pouvez compter sur l'arrière tout assez commun, est considéré comme rompu sous Posix.\n
Vous n'avez pas besoin|| [[ -n $line ]]
dans lawhile
boucle.)Plus à la FAQ BASH
la source
Si vous ne voulez pas que votre lecture soit interrompue par un caractère de nouvelle ligne, utilisez -
Exécutez ensuite le script avec le nom de fichier comme paramètre.
la source
la source
Voici mon exemple réel comment boucler des lignes d'une autre sortie de programme, vérifier les sous-chaînes, supprimer les guillemets doubles de la variable, utiliser cette variable en dehors de la boucle. Je suppose que beaucoup posent ces questions tôt ou tard.
Déclarez la variable en dehors de la boucle, définissez la valeur et utilisez-la en dehors de la boucle nécessite de faire <<< "$ (...)" syntaxe . L'application doit être exécutée dans un contexte de console actuelle. Les citations autour de la commande gardent les nouvelles lignes du flux de sortie.
La correspondance de boucle pour les sous-chaînes lit ensuite la paire nom = valeur , divise la partie droite du dernier caractère = , supprime la première citation, supprime la dernière citation, nous avons une valeur propre à utiliser ailleurs.
la source
Cela arrive assez tard, mais avec l'idée que cela peut aider quelqu'un, j'ajoute la réponse. De plus, ce n'est peut-être pas la meilleure façon.
head
La commande peut être utilisée avec un-n
argument pour lire n lignes depuis le début du fichier et latail
commande peut également être utilisée pour lire depuis le bas. Maintenant, pour récupérer la nième ligne du fichier, nous dirigeons n lignes , redirigeons les données vers une seule ligne à partir des données canalisées.la source
sed
ouhead
+tail
est incroyablement inefficace, et pose bien sûr la question de savoir pourquoi vous n'utilisez pas simplement l'une des autres solutions ici. Si vous devez connaître le numéro de ligne, ajoutez un compteur à votrewhile read -r
boucle ou utiliseznl -ba
pour ajouter un préfixe de numéro de ligne à chaque ligne avant la boucle.J'aime utiliser
xargs
au lieu dewhile
.xargs
est puissant et convivial en ligne de commandecat peptides.txt | xargs -I % sh -c "echo %"
Avec
xargs
, vous pouvez également ajouter de la verbosité-t
et une validation avec-p
la source
@Peter: Cela pourrait fonctionner pour vous-
Cela retournerait la sortie-
la source