2016-03-29 5 views
1

Angenommen, ich Datei data genannt haben:Wie lösche Zeilen, die eine Zeichenfolge aus einer anderen Datei enthalten?

ID_11 0.3 0.5 
ID_13 0.5 0.5 
ID_14 0.6 0.3 
ID_15 0.7 0.8 
ID_16 0.9 1.0 

Ich habe auch eine andere Datei ID:

ID_11 
ID_16 

Ich möchte löschen Sie die Zeilen in data, wo die erste Spalte der Zeile entspricht ID. Der gewünschte Ausgang ist wie folgt:

ID_13 0.5 0.5 
ID_14 0.6 0.3 
ID_15 0.7 0.8 

Wie geht das?

Ich habe einen Befehl online gefunden. Aber ich weiß nicht, ob es richtig ist oder nicht. Kann jemand eine Erklärung geben?

awk 'FNR==NR{a[$1];next} !($1 in a)' ID file 
+0

Lesen Sie zuerst die ID-Datei und verwenden Sie die IDs als Schlüssel eines Arrays. Lesen Sie dann die Datendatei, prüfen Sie, ob '$ 1' nicht im Array ist, und drucken Sie die Zeile. – Barmar

+0

@ 81235 - Was hast du schon probiert? – Soren

+2

Sie können auch 'grep -v -f ID data' verwenden. – Barmar

Antwort

1

Ihr Befehl sieht mir gut, und es funktioniert auch für mich, lassen Sie mich den Befehl erklären:

$cat file1                       
ID_11 0.3 0.5 
ID_13 0.5 0.5 
ID_14 0.6 0.3 
ID_15 0.7 0.8 
ID_16 0.9 1.0 
$cat file2                       
ID_11 
ID_16 
$awk 'NR==FNR{a[$1]++;next} !($1 in a)' file2 file1             
ID_13 0.5 0.5 
ID_14 0.6 0.3 
ID_15 0.7 0.8 
  1. NR==FNR NR Anzahl der Datensatz wird es hält erhöhen, wenn Sie eine lesen oder mehr Dateien, es ist die Gesamtzahl der Datensätze; FNR ist die Dateinummer des Datensatzes, den er beim Lesen einer Datei erhöht, und beim Lesen einer anderen Datei auf 0 zurückgesetzt wird, ist dies die aktuelle Datensatznummer.

  2. a[$1]++;next Wenn es keinen FS (Feldtrenn) vorgesehen ist, ist der Standardtrennraum, in Ihrem Fall FS Raum ist daher keine Notwendigkeit, es zu schaffen. setzen Feld 1 (ID_XX) in Array a als Indexnummer, der Rest überspringen next

  3. !($1 in a) ausführen verwenden, wenn die zweite Datei liest, und wenn das Feld 1 nicht in Array a, ausdrucken.

+0

Das ist derselbe awk-Befehl, den er in die Frage eingegeben hat. – Barmar

+0

Können Sie detaillierte Erläuterungen zu Ihrem Befehl geben? – 81235

+0

@ 81235 sehe meine Bearbeitung – haifzhan

-1
for line in $(cat ID); do sed '/$line/d' data; done 

Ich bin nicht sicher, wie Iteration auf Ihre speziellen Schale erfolgt, sondern etwas auf den Linien der oben genannten.

+0

Das ist so falsch. Es wird die Datendatei mehrfach gedruckt, wobei jedes Mal nur eine Zeile übersprungen wird. – Barmar

+0

Was meinen Sie mit "seiner spezifischen Shell"? Die Frage ist mit 'bash' markiert, in' bash' gibt es keinen 'foreach' Befehl. – Barmar

1

Dieser Teil des Skripts:

NR==FNR{a[$1]++;next} 

speichert die Werte aus der ID-Datei in das Array a.

FNR ist die Zeilennummer in der aktuellen Datei, NR ist die Zeilennummer in allen Eingabedateien. Wenn sie gleich sind, bedeutet dies, dass Sie die erste Datei verarbeiten. Das ist ein übliches Idiom, das Sie in vielen Skripten sehen, in denen die erste Datei eine besondere Rolle spielt.

a[$1]++ verwendet das erste Feld als Schlüssel eines Arrays und inkrementiert dieses Arrayelement. Dadurch wird das Array-Element bei Bedarf erstellt.

next geht zur nächsten Zeile in der Eingabe, so überspringt es andere Codeblöcke.

!($1 in a) 

wird bei der Verarbeitung der zweiten Eingabedatei ausgeführt.Es testet, ob das erste Feld kein Schlüssel in dem Array ist, das während der Verarbeitung der ersten Datei erstellt wurde. Da es keinen Codeblock gibt, ist die Standardaktion, wenn ein Test wahr ist, das Drucken der Eingabezeile.

1

Sie können das tun mit grep:

$ grep -vFwf ID data 
ID_13 0.5 0.5 
ID_14 0.6 0.3 
ID_15 0.7 0.8 

Die Optionen wie folgt vor:

  • -v: Invert-Spiele – drucken die Zeilen, die nicht Spiel
  • -F: feste Zeichenfolgen – interpretieren Muster nicht als regulärer Ausdruck (das Ergebnis wird hier nicht geändert, möglicherweise beschleunigt te die Dinge ein wenig)
  • -w: Wort passend – nur Linien entsprechen dem das Spiel ein ganzes Wort ist (verhindert passende substring)
  • -f: lesen Muster aus der Datei – interpretieren Argument als Dateiname statt Muster
1

Sie können es mit join tun:

join -v 1 data ID 

standardmäßig join verwendet das erste Feld für die beiden Dateien. Der Parameter -v 1 zeigt nur unpaare Zeilen aus der ersten Datei an.

Verwandte Themen