Qual è un buon modo per estrarre dire, righe 20 -45 da un enorme file di testo. Naturalmente non interattivamente!
Qual è un buon modo per estrarre dire, righe 20 -45 da un enorme file di testo. Naturalmente non interattivamente!
Risposte:
potresti provare:
cat textfile | head -n 45 | tail -n 26
o
cat textfile | awk "20 <= NR && NR <= 45"
aggiornare:
Come ha sottolineato Mahomedalid, cat
non è necessario e un po 'ridondante, ma rende un comando pulito e leggibile.
Se cat
ti dà fastidio, un sollution migliore sarebbe:
<textfile awk "20 <= NR && NR <= 45"
,
operatore di intervallo di awk .
Ancora più semplice:
sed -n '20,45p;45q' < textfile
Il flag -n disabilita l'output predefinito. "20,45" indica le righe da 20 a 45, incluso. Il comando "p" stampa la riga corrente. E la q si chiude dopo aver stampato la linea.
q
comando (tutto a partire da ;
) ha migliorato le prestazioni per me durante l'estrazione di una singola riga 26995107 da un file 27169334.
Questa non è una risposta, ma non è possibile pubblicarla come commento.
Un altro modo (molto veloce) per farlo è stato suggerito da mikeserv qui :
{ head -n 19 >/dev/null; head -n 26; } <infile
Utilizzando lo stesso file di test qui e la stessa procedura, ecco alcuni parametri di riferimento (estrazione delle righe 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
Queste sono di gran lunga le soluzioni più veloci e le differenze sono trascurabili (per un singolo passaggio) (ho provato con intervalli diversi: un paio di linee, milioni di linee ecc.).
Farlo senza la pipa potrebbe offrire un vantaggio significativo, tuttavia, a un'applicazione che doveva cercare su più gamme di linee in modo simile, come:
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
... che stampa ...
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
... e legge il file solo una volta.
Le altre sed
/ awk
/ perl
soluzioni leggono l'intero file e poiché si tratta di file enormi, non sono molto efficienti. Ho lanciato alcune alternative che exit
o q
uit dopo l'ultima riga nell'intervallo specificato:
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
nel tuo sistema.
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]'
? :-P Questo è qualcosa che Ruby, modellato sul Perl, ispirato a awk / sed, può fare facilmente.
Poiché sed e awk sono già stati presi, ecco una soluzione perl:
perl -nle "print if ($. > 19 && $. < 46)" < textfile
Oppure, come sottolineato nei commenti:
perl -ne 'print if 20..45' textfile
perl -ne'print if 20..45' textfile
awk NR==20,NR==45 textfile
funziona anche e legge facilmente.