linux - une - Boucler le contenu d'un fichier dans Bash




taille fichier linux (8)

@Peter: Cela pourrait fonctionner pour vous-

echo "Start!";for p in $(cat ./pep); do
echo $p
done

Cela retournera la sortie

Start!
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

Comment puis-je parcourir chaque ligne d'un fichier texte avec Bash ?

Avec ce script:

echo "Start!"
for p in (peptides.txt)
do
    echo "${p}"
done

Je reçois cette sortie à 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 sortie:

GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

Sortie de cat /proc/version :

Linux version 2.6.18.2-34-default ([email protected]) (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

Ce n'est pas mieux que d'autres réponses, mais c'est un moyen de plus de faire le travail dans un fichier sans espace (voir les commentaires). Je trouve que j'ai souvent besoin d'un interligne pour parcourir des listes dans des fichiers texte sans avoir à utiliser des fichiers script séparés.

for word in $(cat peptides.txt); do echo $word; done

Ce format me permet de tout mettre en ligne de commande. Remplacez la partie "echo $ word" par ce que vous voulez et vous pouvez lancer plusieurs commandes séparées par des points-virgules. L'exemple suivant utilise le contenu du fichier en tant qu'argument dans deux autres scripts que vous avez écrits.

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done

Ou si vous avez l'intention de l'utiliser comme un éditeur de flux (apprendre sed), vous pouvez vider la sortie vers un autre fichier comme suit.

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done > outfile.txt

J'ai utilisé ceux-ci comme indiqué 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:

OLDIFS=$IFS; IFS=$'\n'; for line in $(cat peptides.txt); do cmd_a.sh $line; cmd_b.py $line; done > outfile.txt; IFS=$OLDIFS

Cela indique simplement à l'interpréteur de commandes de ne partager que sur les retours à la ligne, et non sur les espaces, puis de ramener l'environnement à ce qu'il était auparavant. À ce stade, vous pouvez envisager de tout mettre dans un script shell plutôt que de tout compresser en une seule ligne, cependant.

Bonne chance!


Si vous ne voulez pas que votre lecture soit interrompue par un caractère de nouvelle ligne, utilisez -

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    echo "$line"
done < "$1"

Ensuite, exécutez le script avec le nom de fichier en tant que paramètre.


Supposons que vous avez ce fichier:

$ cat /tmp/test.txt
Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR

Il y a quatre éléments qui vont modifier la signification de la sortie du fichier lu par de nombreuses solutions Bash:

  1. La ligne vide 4;
  2. Espaces de début ou de fin sur deux lignes;
  3. Maintenir la signification des lignes individuelles (c.-à-d. Que chaque ligne est un enregistrement);
  4. La ligne 6 n'est pas terminée avec un CR.

Si vous voulez que le fichier texte ligne par ligne, y compris les lignes vierges 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 (en comparaison de ce que le cat retourne):

1) Perdre la dernière ligne et les espaces de début et de fin:

$ while read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'

(Si vous faites while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt place, vous préservez les espaces de while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt et de fin mais perdez la dernière ligne si il n'est pas terminé avec CR)

2) L'utilisation de la substitution de processus avec cat lit le fichier entier en une seule gorgée et perd la signification des lignes individuelles:

$ for p in "$(cat /tmp/test.txt)"; do printf "%s\n" "'$p'"; done
'Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR'

(Si vous supprimez le " de $(cat /tmp/test.txt) vous lisez le fichier mot par mot plutôt qu'un seul gulp. 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 la suivante:

$ while IFS= read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'    Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space    '
'Line 6 has no ending CR'

Si vous souhaitez supprimer les espaces de début et de fin, supprimez la partie IFS= :

$ while read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'
'Line 6 has no ending CR'

(Un fichier texte sans terminaison \n , bien que relativement commun, est considéré comme cassé sous POSIX.) Si vous pouvez compter sur le \n vous n'avez pas besoin de || [[ -n $line ]] dans la boucle while.)

Plus à la FAQ BASH



Voici mon exemple de la vie réelle comment boucler les lignes d'une autre sortie du programme, vérifier les sous-chaînes, supprimer les doubles quotes de la variable, utiliser cette variable en dehors de la boucle. Je suppose que beaucoup posent ces questions tôt ou tard.

##Parse FPS from first video stream, drop quotes from fps variable
## streams.stream.0.codec_type="video"
## streams.stream.0.r_frame_rate="24000/1001"
## streams.stream.0.avg_frame_rate="24000/1001"
FPS=unknown
while read -r line; do
  if [[ $FPS == "unknown" ]] && [[ $line == *".codec_type=\"video\""* ]]; then
    echo ParseFPS $line
    FPS=parse
  fi
  if [[ $FPS == "parse" ]] && [[ $line == *".r_frame_rate="* ]]; then
    echo ParseFPS $line
    FPS=${line##*=}
    FPS="${FPS%\"}"
    FPS="${FPS#\"}"
  fi
done <<< "$(ffprobe -v quiet -print_format flat -show_format -show_streams -i "$input")"
if [ "$FPS" == "unknown" ] || [ "$FPS" == "parse" ]; then 
  echo ParseFPS Unknown frame rate
fi
echo Found $FPS

Déclarer la variable en dehors de la boucle, définir la valeur et l'utiliser en dehors de la boucle nécessite une syntaxe <<< "$ (...)" . L'application doit être exécutée dans un contexte de la console actuelle. Les citations autour de la commande gardent les nouvelles lignes du flux de sortie.

Loop correspond à la sous-chaîne puis lit la paire nom = valeur , divise la partie droite du dernier = caractère, laisse tomber la première citation, laisse tomber la dernière citation, nous avons une valeur propre à utiliser ailleurs.


#!/bin/bash
#
# Change the file name from "test" to desired input file 
# (The comments in bash are prefixed with #'s)
for x in $(cat test.txt)
do
    echo $x
done

cat peptides.txt | while read line
do
   # do something with $line here
done




io