Qual è il modo migliore per estrarre un segmento da un file di testo?


Risposte:


12

potresti provare:

cat textfile | head -n 45 | tail -n 26

o

cat textfile | awk "20 <= NR && NR <= 45" 

aggiornare:

Come ha sottolineato Mahomedalid, catnon è necessario e un po 'ridondante, ma rende un comando pulito e leggibile.

Se catti dà fastidio, un sollution migliore sarebbe:

<textfile awk "20 <= NR && NR <= 45"

2
awk NR==20,NR==45 textfilefunziona anche e legge facilmente.
effimero

Mi piace di più l'uso di stdin, ha una certa coerenza globale con il resto di nix
Stefan,

1
La lettura dagli argomenti della riga di comando è coerente anche con altre utility UNIX e il mio punto principale era dimostrare l' ,operatore di intervallo di awk .
effimero

lol, intendevo @adam. ma sì, mi piace il tuo suggerimento
Stefan

Penso che la risposta di @ephemient sia la migliore qui. Altrimenti, i comandi sono piuttosto criptici.
Léo Léopold Hertz

13

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.


1
+1 simpatico, mi piace, ma la sua linea 20 a 45 :)
Stefan

1
ok ok, l'ho modificato per dire 20,45 :-)
dkagedal,

La rimozione del qcomando (tutto a partire da ;) ha migliorato le prestazioni per me durante l'estrazione di una singola riga 26995107 da un file 27169334.
Ruslan,

6

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/ perlsoluzioni leggono l'intero file e poiché si tratta di file enormi, non sono molto efficienti. Ho lanciato alcune alternative che exito quit 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

+1 Penso che questa sia la migliore risposta qui! Sarebbe bello ottenere quanto tempo ci vuole awk NR==1000020,NR==1000045 textfilenel tuo sistema.
Léo Léopold Hertz

3
ruby -ne 'print if 20 .. 45' file

1
un collega rubyist, mi fai votare signore
Stefan,

1
Mentre ci siamo, perché no 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.
effimero

2

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

2
Cosa c'è con tutti quei personaggi extra? Non è necessario eseguire lo striping e aggiungere nuovamente le nuove righe, il flip-flop presuppone il confronto con il numero di riga e l'operatore diamond esegue gli argomenti se forniti. perl -ne'print if 20..45' textfile
effimero

1
Bello. -nle è un po 'un riflesso suppongo, per il resto non ho scuse se non l'ignoranza.
Steven D,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.