2012-04-26 6 views
9

Wahrscheinlich ist dies eine sehr grundlegende Frage für Shell-Programmierer. Angenommen, ich habe eine Textdatei A und B und B ist eine Teilmenge von A.grundlegende Shell-Programmierung

Ich möchte eine Textdatei C erstellen, die (A-B) Daten enthält.

Also alle gemeinsamen Zeilen weglassen.

Die Zeile in Dateien sind numerische Daten: wie

id , some aspect, other aspec. 

Dank.

+0

Sie haben nicht erwähnt, so oder so, ob Ihre Daten doppelte Zeilen enthalten. Wenn es möglich ist, dann beachte, dass Tim Potes Methode 'sort' +' uniq' ** nicht funktioniert **, wenn es in "A" unübertroffene duplizierte Zeilen gibt. Die 'awk' und' comm' Methoden funktionieren mit Duplikaten in 'A'. –

Antwort

12

Verwenden sort und uniq

sort a b | uniq -u 

Wenn Sie die Linien wollen, die gleich zwischen A und B sind, können Sie uniq -d

sort a b | uniq -d 

Dies setzt natürlich verwenden, dass die Daten in A und B sind genau gleich. In den Datasets dürfen keine Leerzeichen oder Tabs enthalten sein. Wenn dies der Fall ist, müssen Sie zuerst die Daten mit sed, tr oder awk bereinigen.

bearbeiten

Als Peter. O wies darauf hin, dies wird fehlschlagen, wenn es genaue Duplikate in der Datei a gibt. Wenn das ein Problem ist, können Sie das Problem beheben, indem Sie diese:

sort <(sort -u a) b | uniq -u 
+0

eine sehr naive Frage. Wie speichere ich es in der Datei "c" ?? – Fraz

+1

Sie müssen die Ausgabe mit '>' umleiten.Der Befehl wäre dann: 'sort a b | uniq -u> c' –

+1

'sort a b | uniq -u> c' – dpp

4

Eine Möglichkeit awk verwenden. Umleiten, um Inhalt in einer beliebigen Datei anstelle von STDOUT zu speichern.

awk 'FNR == NR { data[ $0 ] = 1; next } FNR < NR { if ($0 in data) { next } print $0 }' fileB fileA 

AKTUALISIERT mit einem effizienteren Befehl. Dank Peter.O:

awk 'FNR==NR{data[$0]; next}; $0 in data{next}; 1' fileB fileA 
+0

Nur ein paar Punkte, um es ein wenig mehr Consise (und schneller) zu machen: 1) Sie müssen keinen Wert zu dem Array zuweisen; nur darauf Bezug nehmend, entsteht der Indexteil. 2) Der zweite FNR-Test wird nicht benötigt, da das vorhergehende 'next' dafür sorgt. 3) Der 'if'-Test ist überflüssig, da $ 0 in Daten ein eigener Test ist. 4) Jeder Wert ungleich Null bewirkt, dass "$ 0" gedruckt wird, so dass der Ausdruck $ 0 ein "boolescher Wert" sein kann: "awk" FNR == NR {data [$ 0]; Nächster}; $ 0 in Daten {next}; 1 'DateiB DateiA' –

+0

@ Peter.O: Vielen Dank für die Vorschläge. Ich addiere deinen Befehl zur Antwort. – Birei

+0

Sie brauchen auch nicht diese NULL-Anweisungen (abschließende Semikolons) und anstatt für $ 0 in Daten zu testen und als nächstes zu tun und dann einen impliziten Druck danach, können Sie einfach den Test negieren, und Sie brauchen nicht die erste weiter (es sei denn, DateiB ist riesig und Effizienz ist ein Problem), so können Sie es einfach schreiben als 'awk' FNR == NR {Daten [$ 0]}! ($ 0 in Daten} 'DateiB DateiA'. –

7

Es gibt ein Dienstprogramm comm genannt, die für eben diese verwendet wird:

comm -23 A B > C 

wo -2 Mittel "lehnen die Linien einzigartige B to file" (Sie sagen, dass es aren 't any), und -3 bedeutet "lehne die für beide Dateien gemeinsamen Zeilen ab".

@BartonChittenden macht einen guten Punkt:

comm -23 <(sort A) <(sort B) > C 
+2

Beachten Sie, dass beide Dateien sein müssen sortierte. –

+0

+1 für das Zeigen von mir 'comm', von dem ich nie gehört hatte. +10 für das Zeigen von mir' <(Befehl) 'das ich nie auch schon gehört hatte. –

+1

Das nennt man" Prozesssubstitution "und lässt dich behandeln Ausgabe eines Befehls, als wäre es eine Datei, siehe die man-Seite. –

2
awk 'FNR==NR{a[$0];next}(!($0 in a))' B A