web-dev-qa-db-fra.com

Comment extraire plusieurs bits d'informations apparaissant sur différentes lignes dans le même fichier texte

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

L'entrée ressemble à

>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... *

La sortie souhaitée est l’ID de séquence dans une colonne et le numéro de cluster correspondant 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 aider avec ça?

8
Tim

Avec awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • nous divisons des champs sur des espaces ou des périodes avec -F '[. ]*'
  • avec des lignes de deux champs (les lignes >Cluster), enregistrez le deuxième champ comme ID et passez à la ligne suivante
  • avec les autres lignes, affiche le troisième champ et l'ID enregistré
13
muru

Vous pouvez utiliser awk pour cela:

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

La première instruction de bloc est la capture de l'ID de cluster. La deuxième instruction de bloc (celle par défaut) extrait les données souhaitées et les affiche.

5
oliv

Voici une alternative avec Ruby comme une ligne:

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

ou répartis sur plusieurs lignes:

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

Je suppose que c'est seulement plus lisible que la version awk si vous connaissez Ruby et regexen. En prime, ce code pourrait être un peu plus robuste que le simple découpage des lignes, car il recherche le texte environnant.

3
Eric Duminil

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: lit le fichier d'entrée ligne par ligne (-n) et applique le script donné par -e à chaque ligne.
  • if(/^>.*?(\d+)/){$n=$1;}: si cette ligne commence par un >, trouvez le plus long tronçon de nombres à la fin de la ligne et enregistrez-le sous le nom $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: si la ligne ne commence pas par >, remplacez le tout par le plus long tronçon de caractères non -. après un > (>[^.]+), c’est-à-dire le nom de la séquence. ($1 parce que nous avons capturé la correspondance d'expression régulière) et la valeur actuelle de $n.

Ou, pour une approche plus proche de la awk:

$ 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

C’est une façon un peu plus lourde de faire la même idée de base que les différentes approches awk. Je l’inclus pour des raisons d’achèvement et pour les fans de Perl. Si vous avez besoin d'explications, utilisez simplement les solutions awk :).

1
terdon