it-swarm.com.de

Extrahieren mehrerer Informationsbits, die in verschiedenen Zeilen in derselben Textdatei angezeigt werden

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

Die Eingabe sieht aus wie

>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 mir jemand dabei helfen?

8
Tim

Mit awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • wir teilen Felder auf Leerzeichen oder Punkte mit -F '[. ]*'
  • speichern Sie bei Zeilen mit zwei Feldern (die Zeilen >Cluster) das zweite Feld als ID und wechseln Sie in die nächste Zeile
  • drucken Sie mit anderen Zeilen das dritte Feld und die gespeicherte ID aus
13
muru

Sie können awk dafü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.

5
oliv

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 verteilen:

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

Ich denke, es ist nur lesbarer als die awk -Version, wenn Sie Ruby kennen und regexen. Als Bonus könnte dieser Code etwas robuster sein, als nur die Zeilen zu teilen, da er nach dem umgebenden Text sucht.

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
_

Erläuterung

  • _Perl -ne_: Liest die Eingabedatei Zeile für Zeile (_-n_) und wendet das Skript von _-e_ auf jede Zeile an.
  • if(/^>.*?(\d+)/){$n=$1;}: Wenn diese Zeile mit einem _>_ beginnt, suchen Sie den längsten Teil der Zahlen am Ende der Zeile und speichern Sie diesen als _$n_.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: Wenn die Zeile nicht mit _>_ beginnt, ersetzen Sie alle Zeichen mit der längsten Länge von Nicht-_._ nach einem _>_ (_>[^.]+_). dh der Sequenzname (_$1_, weil wir erfasst die Regex-Übereinstimmung haben) und den aktuellen Wert von _$n_.

Oder, für einen 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 nur eine etwas umständlichere Art, die gleiche Grundidee wie die verschiedenen awk -Ansätze zu verwirklichen. Ich beziehe es der Vollständigkeit halber und für die Perl-Fans mit ein. Wenn Sie eine Erklärung benötigen, verwenden Sie einfach die awk-Lösungen :).

1
terdon