
Ich habe eine Textdatei mit Zeichenfolgen/Dateinamen in separaten Zeilen, z. B. filename.txt
. Es gibt Hunderte von Dateinamen
ABC123_S386_R1_001
JKL345_S441_R1_001
filename9000_S587_R1_001
und eine weitere Textdatei mit den Zeichenfolgen/Dateinamen und zusätzlichen Daten, z. B results.txt
.:
>ABC123_S386_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>JKL345_S441_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>abc7890_S387_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>filename9000_S587_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
Nun filename.txt
sind nicht alle Dateinamen in vorhanden und auch nicht in der richtigen Reihenfolge. Ich möchte allen Dateinamen von bis results.txt
ein Präfix hinzufügen, aber nicht den anderen.filename.txt
results.txt
Wie lese ich eine Eingabedatei mit Zeichenfolgen, vergleiche sie mit einer anderen Datei und ändere die Übereinstimmungen?
Früher habe ich einzelne Dateinamen mit abgeglichen sequence.txt
, ihre Zeilennummer ermittelt und sed
mit Zeilennummern entweder eine einzelne Zeile oder einen Zeilenblock geändert.
Meine gewünschte Ausgabe würde so aussehen
>h-19/US/CA-ABC123_S386_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>h-19/US/CA-JKL345_S441_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>abc7890_S387_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
>h-19/US/CA-filename9000_S587_R1_001
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
wo h-19/US/CA-
ist das Suffix, das ich allen Übereinstimmungen hinzufügen möchte.
Bearbeiten: >
ist das erste Zeichen aller Zeichenfolgen, die geändert werden müssen. Vor dem Dateinamen stehen keine Zeichen >
und nach dem Dateinamen sind auch keine nachstehenden Leerzeichen zu sehen.
Antwort1
Vorausgesetzt, dass die relevanten Zeilen results.txt
nach dem Dateinamen keine Leerzeichen enthalten, awk
funktioniert das folgende Programm:
awk -v prefix="h-19/US/CA-" 'NR==FNR{fnames[$1]; next} \
/^>/{name=substr($0,2); if (name in fnames) {sub(/^>/, ">" prefix)} }1' filenames.txt results.txt
- Dadurch wird zuerst analysiert
filenames.txt
und dannresults.txt
. - Während der Analyse
filenames.txt
(wobeiFNR
der Zeilenzähler pro Datei gleichNR
dem globalen Zeilenzähler ist) werden alle Dateinamen (die die einzigen Felder in der Zeile sind) in einem Array registriertfnames
, die Ausführung dann aber sofort zur nächsten Zeile übersprungen. - Beim Parsen
results.txt
wird geprüft, ob eine Zeile mit beginnt>
. Wenn ja, wird geprüft, ob die Teilzeichenfolge, die diesem Zeichen folgt (vorübergehend in gespeichertname
), unter den „Array-Indizes“ von gefunden wirdfnames
. Wenn dies der Fall ist, wirdsub()
das führende>
durch +das Präfix ersetzt, das als Variable>
übergeben wurde (über die Direktive).awk
prefix
-v
- Der scheinbare „Verirrte“
1
weist an,awk
die aktuelle Zeile einschließlich aller möglichen Änderungen auszudrucken (aber nur, weilresults.txt
wir diesen Teil bei der Verarbeitung der ersten Datei nicht erreichen).
Beachten Sie, dass awk
es selbst keine Dateien direkt ändern kann, Sie müssen also mit einer temporären Datei arbeiten. Wenn Sie eine ausreichend neue Version von GNU Awk (> 4.1.0) haben, können Sie die Erweiterung jedoch verwenden ; natürlich müssen Sie dann die Option für die Datei inplace
deaktivieren :filenames.txt
awk -i inplace -v prefix=" ... " ' ... ' inplace=0 filenames.txt inplace=1 results.txt
Dadurch wird die direkte Bearbeitung für deaktiviert filenames.txt
und für wieder aktiviert results.txt
.
Antwort2
Mit sed
können Sie die Dateinamen im Haltebereich sammeln und dann alle Zeilen auf results.txt
Übereinstimmungen prüfen, um herauszufiltern, welche Zeilen geändert werden sollen:
sed -e '1,/^$/{H;1h;d;}' -e 'G;/^>\(.*\).*\n\1\n/s_^>_>h-19/US/CA-_;P;d' filename.txt <((echo)) results.txt
<((echo))
Ihr seht, dass ich zwischen den Dateien eine Leerzeile mitgebe , die1,/^$/
alle Zeilen der ersten Datei (und die Leerzeile) anspricht.- Diese Zeilen werden an den Haltebereich angehängt und dann gelöscht
H;1h;d
(1h
vermeidet, den Haltebereich mit einer neuen Zeile zu beginnen). G
hängt den Haltebereich an alle Zeilen von anresult.txt
und/^>\(.*\).*\n\1\n/
gleicht die Zeilen ab, die mit und einer Zeichenfolge beginnen>
, die ein Dateiname ist (im Haltebereich in Zeilenumbrüche eingeschlossen)s_^>_>h-19/US/CA-_
ersetzt diese ZeileP;d
druckt nur die erste Zeile ohne den angehängten Müll. Sie könntens/\n.*//
stattdessen
Antwort3
perl
Für direkte Änderungen an der Eingabedatei verwenden :
pfx='h-19/US/CA-' \
perl -pi -e '
BEGIN { %h = map { tr/\n//dr => $ENV{pfx}} <STDIN>}
s/^>\K(?=(.*))/$h{$1}/;
' results.txt < filename.txt