Was ist ein guter Weg, um beispielsweise Zeilen 20 bis 45 aus einer riesigen Textdatei zu extrahieren? Natürlich nicht interaktiv!
Was ist ein guter Weg, um beispielsweise Zeilen 20 bis 45 aus einer riesigen Textdatei zu extrahieren? Natürlich nicht interaktiv!
Antworten:
du könntest es versuchen:
cat textfile | head -n 45 | tail -n 26
oder
cat textfile | awk "20 <= NR && NR <= 45"
aktualisieren:
Wie Mahomedalid betonte, cat
ist dies nicht notwendig und etwas überflüssig, sorgt jedoch für einen sauberen, lesbaren Befehl.
Wenn Sie cat
das stört, wäre eine bessere Lösung:
<textfile awk "20 <= NR && NR <= 45"
,
Bereichsoperator von awk zu demonstrieren .
Noch einfacher:
sed -n '20,45p;45q' < textfile
Das Flag -n deaktiviert die Standardausgabe. Die "20,45" adressiert die Zeilen 20 bis einschließlich 45. Der Befehl "p" druckt die aktuelle Zeile. Und das q wird nach dem Drucken der Zeile beendet.
q
Befehls (alles ab ;
) verbesserte die Leistung für mich beim Extrahieren einer einzelnen Zeile 26995107 aus einer Datei mit 27169334 Zeilen.
Dies ist keine Antwort, kann aber nicht als Kommentar veröffentlicht werden.
Ein anderer (sehr schneller) Weg, dies zu tun, wurde von mikeserv hier vorgeschlagen :
{ head -n 19 >/dev/null; head -n 26; } <infile
Unter Verwendung der gleichen Testdatei wie hier und des gleichen Verfahrens finden Sie hier einige Benchmarks (Extrahieren der Zeilen 1000020-1000045):
mikeserv :
{ head -n 1000019 >/dev/null; head -n 26; } <iplist
real 0m0.059s
Stefan :
head iplist -n 1000045 | tail -n 26
real 0m0.054s
Dies sind bei weitem die schnellsten Lösungen und die Unterschiede sind vernachlässigbar (für einen einzelnen Durchgang) (ich habe es mit verschiedenen Bereichen versucht: ein paar Zeilen, Millionen von Zeilen usw.).
Ein Verzicht auf das Rohr kann jedoch einen erheblichen Vorteil für eine Anwendung bieten, die auf ähnliche Weise über mehrere Linienbereiche hinweg suchen muss , z.
for pass in 0 1 2 3 4 5 6 7 8 9
do printf "pass#$pass:\t"
head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES
... was druckt ...
pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000
... und liest die Datei nur einmal durch.
Die anderen sed
/ awk
/ perl
Lösungen lesen Sie die gesamte Datei und da diese über große Dateien ist, sie sind nicht sehr effizient. Ich warf in einigen Alternativen dass exit
oder q
uit nach der letzten Zeile im angegebenen Bereich:
Stefan :
awk "1000020 <= NR && NR <= 1000045" iplist
real 0m2.448s
vs.
awk "NR >= 1000020;NR==1000045{exit}" iplist
real 0m0.243s
dkagedal ( sed
):
sed -n 1000020,1000045p iplist
real 0m0.947s
vs.
sed '1,1000019d;1000045q' iplist
real 0m0.143s
Steven D :
perl -ne 'print if 1000020..1000045' iplist
real 0m2.041s
vs.
perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist
real 0m0.369s
awk NR==1000020,NR==1000045 textfile
in Ihrem System kostet.
ruby -ne 'print if 20 .. 45' file
python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'
auch, wenn wir schon dabei sind ? :-P Dies ist etwas, was Ruby, nach dem Vorbild von Perl, inspiriert von awk / sed, leicht tun kann.
Da sed und awk bereits eingenommen wurden, ist hier eine Perl-Lösung:
perl -nle "print if ($. > 19 && $. < 46)" < textfile
Oder, wie in den Kommentaren ausgeführt:
perl -ne 'print if 20..45' textfile
perl -ne'print if 20..45' textfile
awk NR==20,NR==45 textfile
funktioniert auch und liest sich leicht.