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
>Cluster
Zeilen) 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 awk
hierfü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 awk
Version, 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-e
auf 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 ($1
weil 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 awk
Ansä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 :).