2014-11-05 2 views
6

Ich habe ein Diff, das im Wesentlichen entweder zusätzliche eindeutige Zeilen oder Zeilen, die in der Datei verschoben wurden, und damit ihre Zeilennummern geändert haben. Um herauszufinden, was wirklich eine neue Ergänzung ist, betreiben ich diesen kleinen Perl-Schnipsel, die ‚gelöst‘ Zeilen aus den ‚ungelöst‘ Linien zu trennen:grep nicht sehr gut auf großen Dateien, gibt es eine Alternative?

perl -n -e' 
    /^\-([^\-].*?)\([^,\(]+,\d+,\d+\).*$/ && do { print STDOUT "$1\n"; next; }; 
    /^\+([^\+].*?)\([^,\(]+,\d+,\d+\).*$/ && do { print STDERR "$1\n"; next; }; 
' "$delta" 1>resolved 2>unresolved 

Das ist ziemlich schnell in der Tat und macht den Job, ein 6000 Trennung + Linie diff in zwei 3000+ Zeilen-Dateien, entfernen Sie alle Verweise auf Zeilennummern und einheitliche diff-Dekoration. Als nächstes kommt der grep-Befehl, der bei 100% CPU zu laufen scheint für fast 9 Minuten (real): im Wesentlichen

grep -v -f resolved unresolved 

Dies wird alle aufgelösten Linien aus der ungelösten Datei zu entfernen. Die Ausgabe, nach 9 Minuten, ist zufällig 9 Zeilen der Ausgabe - die eindeutigen Ergänzungen oder unaufgelösten Zeilen.

Erstens, wenn ich Grep in der Vergangenheit benutzt habe, war es ziemlich gut, also warum ist es in diesem Fall außergewöhnlich langsam und CPU-hungrig?

Zweitens gibt es eine effizientere Alternative zum Entfernen von Zeilen aus einer Datei, die in einer anderen enthalten sind?

+0

Okay, ich denke, ich habe meine eigene Frage ein wenig mit den Zahlen beantwortet. Grep analysiert 3000 Zeilen einer Datei, möglicherweise 3000 mal, also vielleicht einer 9.000.000 Zeilen großen Datei. Aber das ist immer noch nicht so groß. Es ist fast so, als würde grep 60 Sekunden brauchen, um 1.000.000 Zeilen zu analysieren. – Craig

+0

Beachten Sie, dass '. * $ 'Nutzlos ist – ikegami

+0

Sicher, aber ich dachte nur^könnte ein wenig einsam ohne ein $ werden. :-) – Craig

Antwort

5

Grep analysiert diese Datei wahrscheinlich vollständig für jedes gefundene Match. Sie können "fgrep" versuchen, wenn es auf Ihrem System vorhanden ist, oder grep -F, wenn dies nicht der Fall ist, was grep dazu zwingt, den Aho-Corasick String-Matching-Algorithmus (http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm) zu verwenden, der alle Strings gleichzeitig abgleicht Durchlaufen der Datei.

+0

Wow, was für ein Unterschied. Hier ist das Timing für die fgrep-Lösung: real 0m0.049s, user 0m0.041s, sys 0m0.009s – Craig

8

Wenn die Linien über die beiden Dateien angepasst werden sollen genau übereinstimmen müssen, können Sie sortieren und uniq verwenden, um die Arbeit zu erledigen:

cat resolved resolved unresolved | sort | uniq -u 

Die einzigen nicht-duplizierte Linien in der Pipeline oben Willen Linien in ungelöst sein, die nicht in aufgelöst sind. Beachten Sie, dass es wichtig ist, aufgelöst zweimal im Befehl cat anzugeben: andernfalls wird das uniq auch Zeilen auswählen, die für diese Datei eindeutig sind. Dies setzt voraus, dass aufgelöst und nicht aufgelöste hatte keine doppelten Zeilen zu beginnen. Aber das ist recht einfach zu bewältigen: gerade Art und uniq sie zuerst

sort resolved | uniq > resolved.uniq 
sort unresolved | uniq > unresolved.uniq 

Auch habe ich festgestellt fgrep zu deutlich schneller, wenn ich versuche, feste Strings übereinstimmen, so dass möglicherweise eine Alternative sein.

+0

Die Lösung "cat resolved resolved unsolved" funktionierte und innerhalb von 1 Sekunde. Ich gebe auch der fgrep-Lösung eine Chance. – Craig

+0

nett! Eine Variante dieses Problems frage ich gelegentlich in Interviews. Es ist immer interessant, die Dinge zu sehen, mit denen die Leute kommen. – RS239

+0

Die fgrep-Lösung scheint etwas schneller, aber marginal. Hier ist das Timing für diese Lösung: real 0m0.220s, Benutzer 0m0.212s, sys \t 0m0.004s – Craig

Verwandte Themen