So extrahieren Sie mehrere Informationsbits, die in verschiedenen Zeilen derselben Textdatei erscheinen

So extrahieren Sie mehrere Informationsbits, die in verschiedenen Zeilen derselben Textdatei erscheinen

Ich versuche, die Sequenz-ID und die Clusternummer zu extrahieren, die in verschiedenen Zeilen derselben Textdatei vorkommen.

Die Eingabe sieht wie folgt aus:

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

Die gewünschte Ausgabe ist die Sequenz-ID in einer Spalte und die entsprechende Clusternummer in der zweiten.

>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

Kann jemand dabei helfen?

Antwort1

Mit awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • Wir teilen Felder auf Leerzeichen oder Punkte mit-F '[. ]*'
  • Bei Zeilen mit zwei Feldern (den >ClusterZeilen) speichern Sie das zweite Feld als ID und wechseln Sie zur nächsten Zeile
  • bei anderen Zeilen das dritte Feld und die gespeicherte ID ausdrucken

Antwort2

Sie können awkhierfür verwenden:

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

Die erste Blockanweisung erfasst die Cluster-ID. Die zweite Blockanweisung (die Standardanweisung) extrahiert die gewünschten Daten und druckt sie aus.

Antwort3

Hier ist eine Alternative mit Ruby als Einzeiler:

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

oder auf mehrere Zeilen verteilt:

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

Ich schätze, es ist nur lesbarer als die awkVersion, wenn Sie Ruby und Regexen kennen. Als Bonus ist dieser Code möglicherweise etwas robuster als das einfache Aufteilen der Zeilen, da er nach dem umgebenden Text sucht.

Antwort4

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

Erläuterung

  • perl -ne: Lesen Sie die Eingabedatei zeilenweise ( -n) und wenden Sie das von angegebene Skript -eauf jede Zeile an.
  • if(/^>.*?(\d+)/){$n=$1;}: Wenn diese Zeile mit einem beginnt >, suchen Sie die längste Zahlenfolge am Ende der Zeile und speichern Sie diese als $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: wenn die Zeile nicht mit beginnt >, ersetzen Sie alles durch die längste Folge von Nicht- .Zeichen nach einem >( >[^.]+), also den Sequenznamen ( $1weil wir habengefangendie Regex-Übereinstimmung) und der aktuelle Wert von $n.

Oder für einen eher awk-ähnlichen Ansatz:

$ 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

Dies ist lediglich eine etwas umständlichere Möglichkeit, die gleiche Grundidee wie bei den verschiedenen awkAnsätzen umzusetzen. Ich füge dies der Vollständigkeit halber und für die Perl-Fans hinzu. Wenn Sie eine Erklärung benötigen, verwenden Sie einfach die awk-Lösungen :).

verwandte Informationen