8 votes

Comment extraire plusieurs éléments d'information apparaissant sur différentes lignes d'un même fichier texte ?

J'essaie d'extraire l'ID de séquence et le numéro de cluster qui apparaissent sur des lignes différentes dans le même fichier texte.

L'entrée se présente comme suit

>Cluster 72
0   319aa, >O311_01007... *
>Cluster 73
0   318aa, >1494_00753... *
1   318aa, >1621_00002... at 99.69%
2   318aa, >1622_00575... at 99.37%
3   318aa, >1633_00422... at 99.37%
4   318aa, >O136_00307... at 99.69%
>Cluster 74
0   318aa, >O139_01028... *
1   318aa, >O142_00961... at 99.69%
>Cluster 75
0   318aa, >O300_00856... *

Le résultat souhaité est l'identifiant de la séquence dans une colonne et le numéro de la grappe correspondante dans la seconde.

>O311_01007  72
>1494_00753  73
>1621_00002  73
>1622_00575  73
>1633_00422  73
>O136_00307  73
>O139_01028  74
>O142_00961  74
>O300_00856  75

Quelqu'un peut-il nous aider ?

13voto

muru Points 180007

Avec awk :

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • nous séparons les champs sur les espaces ou les points avec -F '[. ]*'
  • avec des lignes de deux champs, (le >Cluster lignes), enregistrer le deuxième champ en tant qu'ID et passer à la ligne suivante
  • avec d'autres lignes, imprimer le troisième champ et l'identifiant enregistré

5voto

oliv Points 455

Vous pouvez utiliser awk pour cela :

awk '/>Cluster/{
      c=$2;
      next
    }{
      print substr($3,2,length($3)-4), c
    }' file

La première déclaration de bloc capture l'ID du cluster. Le deuxième bloc d'instructions (celui par défaut) extrait les données souhaitées et les imprime.

4voto

Voici une alternative avec Ruby en guise de one-liner :

ruby -ne 'case $_; when /^>Cluster (\d+)/;id = $1;when /, (>\w{4}_\w{5})\.\.\./;puts "#{$1} #{id}";end' input_file

ou sur plusieurs lignes :

ruby -ne 'case $_
when /^>Cluster (\d+)/
  id = $1
when /, (>\w{4}_\w{5})\.\.\./
  puts "#{$1} #{id}"
end' input_file

Je suppose qu'il est seulement plus lisible que le awk si vous connaissez Ruby et les regexen. En prime, ce code peut être un peu plus robuste que le simple découpage des lignes, car il prend en compte le texte environnant.

1voto

Stewart Points 1385

Perl :

$ perl -ne 'if(/^>.*?(\d+)/){$n=$1;}else{ s/.*(>[^.]+).*/$1 $n/; print}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Explication

  • perl -ne : lire le fichier d'entrée ligne par ligne ( -n ) et appliquer le script donné par -e à chaque ligne.
  • if(/^>.*?(\d+)/){$n=$1;} : si cette ligne commence par un > trouver la plus longue suite de chiffres à l'extrémité de la ligne, et la sauvegarder sous le nom de $n .
  • else{ s/.*(>[^.]+).*/$1 $n/; print Si la ligne ne commence pas par > Remplacer le tout par le plus long tronçon de non . à la suite d'un > ( >[^.]+ ), c'est-à-dire le nom de la séquence ( $1 parce que nous avons capturé la correspondance de l'expression rationnelle) et la valeur actuelle de $n .

Ou encore, pour une approche plus proche de la réalité :

$ perl -lane 'if($#F==1){$n=$F[1]}else{$F[2]=~s/\.+$//; print "$F[2] $n"}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Il s'agit simplement d'une manière un peu plus lourde d'appliquer la même idée de base que les différents systèmes de gestion de l'information. awk approches. Je l'inclus pour compléter l'information et pour les fans de Perl. Si vous avez besoin d'une explication, utilisez simplement les solutions awk :).

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X