Linux-Shell-Befehl zum Filtern einer Textdatei nach Zeilenlänge

19

Ich habe ein 30-GB-Festplatten-Image einer verteilten Partition (glaube ich dd if=/dev/sda1 of=diskimage), von der ich einige Textdateien wiederherstellen muss. Daten-Carving-Tools foremostfunktionieren zum Beispiel nur mit Dateien mit klar definierten Kopfzeilen, also nicht mit einfachen Textdateien. Deshalb habe ich mich auf meinen guten Freund verlassen strings.

strings diskimage > diskstrings.txt produzierte eine 3 GB große Textdatei, die eine Reihe von Zeichenfolgen enthielt, meistens nutzloses Zeug, gemischt mit dem Text, den ich eigentlich haben möchte.

Der größte Teil der Kruft besteht aus langen, ungebrochenen Kauderwelschfäden. Das Material, an dem ich interessiert bin, ist garantiert kleiner als 16 KB, also werde ich die Datei nach Zeilenlänge filtern. Hier ist das Python-Skript, mit dem ich das mache:

infile  = open ("infile.txt" ,"r");
outfile = open ("outfile.txt","w");
for line in infile:
    if len(line) < 16384:
        outfile.write(line)
infile.close()
outfile.close()

Dies funktioniert, aber zum späteren Nachschlagen: Gibt es magische einzeilige Beschwörungsformeln (think awk, sed), die eine Datei nach Zeilenlänge filtern würden?

Li-aung Yip
quelle

Antworten:

28
awk '{ if (length($0) < 16384) print }' yourfile >your_output_file.txt

würde Zeilen drucken, die kürzer als 16 Kilobyte sind, wie in Ihrem Beispiel.

Oder wenn Sie Lust auf Perl haben:

perl -nle 'if (length($_) < 16384) { print }' yourfile >your_output_file.txt
Janne Pikkarainen
quelle
Nun, das war peinlich einfach. Vielen Dank. :)
Li-aung Yip
Perl-Version hinzugefügt :-)
Janne Pikkarainen
Und das awk-Skript kann wie awk 'length($0) < 16384' file > outputfolgt geschrieben werden : Die Standardaktion besteht darin, die Zeile zu drucken.
Glenn Jackman
8

Dies ähnelt der Antwort von Ansgar, ist jedoch in meinen Tests etwas schneller:

awk 'length($0) < 16384' infile >outfile

Es ist die gleiche Geschwindigkeit wie die anderen awk Antworten. Es basiert auf dem Implizit printeines wahren Ausdrucks, braucht sich jedoch nicht die Zeit zu nehmen, um die Zeile wie bei Ansgar zu teilen.

Beachten Sie, dass AWK Ihnen eine ifkostenlose gibt. Der obige Befehl entspricht:

awk 'length($0) < 16384 {print}' infile >outfile

Es gibt keine expliziten if(oder die umgebenden geschweiften Klammern) wie in einigen anderen Antworten.

Hier ist eine Möglichkeit, dies zu tun sed:

sed '/.\{16384\}/d' infile >outfile

oder:

sed -r '/.{16384}/d' infile >outfile

die jede Zeile löschen, die 16384 (oder mehr) Zeichen enthält.

Der Vollständigkeit halber verwenden Sie die folgenden Methoden sed, um Zeilen zu speichern, die länger als Ihr Schwellenwert sind:

sed '/^.\{0,16383\}$/d' infile >outfile
Bis auf weiteres angehalten.
quelle
2

Sie können awkwie folgt vorgehen :

$ awk '{ if (length($0) < 16384) { print } }' /path/to/text/file

Dadurch werden die Zeilen gedruckt, die kürzer als 16 KB (16 * 1024) sind.

Sie können grepauch verwenden:

$ grep ".\{,16384\}" /path/to/text/file

Dadurch werden die Zeilen mit maximal 16 KByte gedruckt.

Khaled
quelle
Ich grepbin mir nicht sicher, ob das eine gute Idee ist - es ist zwar ein einfacher regulärer Ausdruck, aber rechenintensiver als awk. "Ein Mann mit einem Problem sagt:" Ich verwende reguläre Ausdrücke! "Jetzt hat er zwei Probleme." ;)
Li-aung Yip
Es ist nur eine andere Art, es zu tun. Die erste Option, die ich gepostet habe, war die Verwendung awk.
Khaled
1
+1 für den regulären Ausdruck, weil es besser Golf spielt, und es macht mich nicht liest awk manpages =)
Ciro Santilli新疆改造中心法轮功六四事件
2

Nicht wirklich anders als die bereits gegebenen Antworten, aber noch kürzer:

awk -F '' 'NF < 16384' infile >outfile
Ansgar Esztermann
quelle