Wie füge ich mit sed für jede Zeile einen anderen Header ein?


7

Ich muss eine Textdatei mit 770 Zeilen ändern und für jede eine andere Überschrift hinzufügen. Ich habe beispielsweise Folgendes:

CWGAGATCGGAAGAGCGGTTCAGCAGGAATGCCGAG
ACACTCTTTCCCTACACGACGCTCTTCCGATCTAGGC
ACACTCTTTCCCTACACGACGCTCTTCCGATCTGATT
ACACTCTTTCCCTACACGACGCTCTTCCGATCTACCGT

Und ich möchte dies erhalten:

>seq1
CWGAGATCGGAAGAGCGGTTCAGCAGGAATGCCGAG
>seq2
ACACTCTTTCCCTACACGACGCTCTTCCGATCTAGGC
>seq3
ACACTCTTTCCCTACACGACGCTCTTCCGATCTGATT
>seq4
ACACTCTTTCCCTACACGACGCTCTTCCGATCTACCGT

Antworten:


13

Da Sie speziell nach einer sed-Lösung gefragt haben (ich würde nicht vorschlagen, dies tatsächlich so zu tun - aber Sie könnten):

$ sed = file | sed '1~2 s/^/>seq/'
>seq1
CWGAGATCGGAAGAGCGGTTCAGCAGGAATGCCGAG
>seq2
ACACTCTTTCCCTACACGACGCTCTTCCGATCTAGGC
>seq3
ACACTCTTTCCCTACACGACGCTCTTCCGATCTGATT
>seq4
ACACTCTTTCCCTACACGACGCTCTTCCGATCTACCGT

Der erste Aufruf sed = filefügt blanke Zeilennummern ein, der zweite verziert sie, indem die >seqZeichenfolge vorangestellt wird .


OTOH Wenn Sie im Voraus wissen, dass es 770 Leitungen gibt, können Sie dies tun

printf ">seq%d\n" {1..770} | sed 'R file'

obwohl dies auf der GNU sed- RErweiterung beruht :

R Dateiname
Warteschlange Eine Zeile mit Dateinamen, die am Ende des aktuellen Zyklus oder beim Lesen der nächsten Eingabezeile gelesen und in den Ausgabestream eingefügt werden soll. Beachten Sie, dass, wenn der Dateiname nicht gelesen werden kann oder wenn sein Ende erreicht ist, keine Zeile ohne Fehleranzeige angehängt wird.

Natürlich , wenn Sie nicht die Anzahl der Zeilen im Voraus wissen, Sie könnten tun

printf ">seq%d\n" $(seq 1 "$(wc -l < file)") | sed 'R file'

Dies würde jedoch den Vorteil verlieren, dass die Datei nur einmal gelesen werden muss.


In der Praxis würde ich wahrscheinlich die awk-Lösung von @ John1024 oder deren Perl-Äquivalent verwenden

perl -lpe 'print ">seq" . $.' file

Netter kluger Einsatz von sed.
John1024

Danke steeldriver für deine nette Erklärung, es hat auch funktioniert. Ich habe nach sed gefragt, weil es der Befehl ist, den ich kenne.
Idalia Rojas

12

Ihre Aufgabe kann mit sed erledigt werden, aber sed fehlt jedes native Verständnis der Arithmetik, was es zum falschen Werkzeug macht. Awk funktioniert gut:

$ awk '{print ">seq" NR} 1' file
>seq1
CWGAGATCGGAAGAGCGGTTCAGCAGGAATGCCGAG
>seq2
ACACTCTTTCCCTACACGACGCTCTTCCGATCTAGGC
>seq3
ACACTCTTTCCCTACACGACGCTCTTCCGATCTGATT
>seq4
ACACTCTTTCCCTACACGACGCTCTTCCGATCTACCGT

Wie es funktioniert:

  • print ">seq" NR

    Für jede neue gelesene Zeile drucken wir zuerst die gewünschte Kopfzeile.

    NR ist awks Zeilenzähler.

  • 1

    Dies ist die kryptische Abkürzung von awk für Print-the-Line.


3
Ich wollte awk vorschlagen
Panther

@steeldriver Der Grund ist, dass ich mir nur einen C ++ - Code <grin> angesehen habe. Ihr Vorschlag ist viel besser. Antwort aktualisiert.
John1024

1
Danke John! Es hat wirklich gut funktioniert. Ich hatte Angst zu fragen, weil ich dachte, es sei eine sehr blöde Frage.
Idalia Rojas

1
Ich bin damit einverstanden, dass dies awkein viel geeigneteres Werkzeug ist. Ein weiteres Beispiel dafür, dass es wichtig ist zu verstehen, was der Kunde braucht - nicht einfach das zu tun, was er verlangt (siehe das berühmte Ford-Zitat "Wenn ich meine Kunden fragen würde, was sie wollen, würden sie" ein schnelleres Pferd "sagen.")
Floris

Für ein weniger kryptisches Awk-Skript verwenden { printf(">seq%d\n%s\n", NR, $0) }.
David Foerster

5

Verwenden einer einfachen Schleife:

count=1; while read -r line ; do printf '>seq%d\n%s\n' $((count++)) "$line"; done < file

Die Ausgabe:

>seq1
CWGAGATCGGAAGAGCGGTTCAGCAGGAATGCCGAG
>seq2
ACACTCTTTCCCTACACGACGCTCTTCCGATCTAGGC
>seq3
ACACTCTTTCCCTACACGACGCTCTTCCGATCTGATT
>seq4
ACACTCTTTCCCTACACGACGCTCTTCCGATCTACCGT

@ John1024 Danke, geändert zu printf;)
Ravexina

0

Verwenden von paste:

 paste -d '\n' <(seq -f '>seq%g' 1 4) file
  • seq -f '>seq%g' 1 4 schreibt durch Zeilenumbrüche getrennte Zahlen in stdout
  • <(...) ist Prozesssubstitution
  • paste Verkettet die entsprechende Zeile jeder Datei, getrennt durch ein Trennzeichen
  • -d '\n' Setzt den Verkettungsbegrenzer auf eine neue Zeile anstelle der Standardregisterkarte

Können Sie die Rolle 1 4im seqBefehl erklären ?
Floris

1
Sie können auch eine anonyme Pipe anstelle eines benannten FIFO verwenden (für eine etwas bessere Leistung oder wenn Ihre Shell keine Prozessersetzung unterstützt):seq -f '>seq%g' 1 4 | paste -d '\n' - file
David Foerster
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.