Supponiamo che io abbia un enorme file di testo (>2 GB) e voglio solo cat
le righe X
a Y
(ad es. da 57890000 a 57890010).
Da quanto ho capito, posso farlo collegando head
in tail
o viceversa, cioè
head -A /path/to/file | tail -B
o in alternativa
tail -C /path/to/file | head -D
dove A
,B
,C
e D
può essere calcolato dal numero di righe nel file, X
e Y
.
Ma ci sono due problemi con questo approccio:
- Devi calcolare
A
,B
,C
eD
. - I comandi potrebbero
pipe
tra loro molti di più righe di quelle che mi interessa leggere (ad es. se sto leggendo solo poche righe nel mezzo di un file enorme)
C'è un modo per far funzionare la shell e produrre le linee che voglio? (pur fornendo solo X
e Y
)?
Risposta accettata:
Suggerisco il sed
soluzione, ma per completezza,
awk 'NR >= 57890000 && NR <= 57890010' /path/to/file
Per tagliare dopo l'ultima riga:
awk 'NR < 57890000 { next } { print } NR == 57890010 { exit }' /path/to/file
Test di velocità (qui su macOS, YMMV su altri sistemi):
- File di 100.000.000 di righe generato da
seq 100000000 > test.in
- Righe di lettura 50.000.000-50.000.010
- Test in ordine sparso
real
tempo come riportato dabash
's built-intime
4.373 4.418 4.395 tail -n+50000000 test.in | head -n10
5.210 5.179 6.181 sed -n '50000000,50000010p;57890010q' test.in
5.525 5.475 5.488 head -n50000010 test.in | tail -n10
8.497 8.352 8.438 sed -n '50000000,50000010p' test.in
22.826 23.154 23.195 tail -n50000001 test.in | head -n10
25.694 25.908 27.638 ed -s test.in <<<"50000000,50000010p"
31.348 28.140 30.574 awk 'NR<57890000{next}1;NR==57890010{exit}' test.in
51.359 50.919 51.127 awk 'NR >= 57890000 && NR <= 57890010' test.in
Questi non sono parametri di riferimento precisi, ma la differenza è abbastanza chiara e ripetibile* da dare un'idea della velocità relativa di ciascuno di questi comandi.
*:Tranne tra i primi due, sed -n p;q
e head|tail
, che sembrano essere essenzialmente gli stessi.