Come funziona `wc -l`?


11

Devo leggere un file di grandi dimensioni e prima di iniziare a leggerlo, devo conoscere il numero totale di righe nel file (che sono in milioni).

Ho implementato molte soluzioni e ne ho trovata una. Ma durante la mia ricerca stavo pensando di vedere come wc -lfunziona. Non sono riuscito a trovare nulla su Google.

Anche se ho trovato una soluzione al mio problema, vorrei comunque sapere come wc -lfunziona poiché può calcolare il numero di righe di un file con 92 milioni di righe in pochi secondi!

Come?


Risposte:


20

Legge l'intero file e conta il numero di fine riga. Il conteggio delle terminazioni di linea è davvero economico; la maggior parte del tempo impiegato è leggere il file. Se il file si trova (principalmente) nella cache del buffer, anche quello sarà economico. In caso contrario, dipenderà dalla velocità di archiviazione dei file.

In altre parole, non c'è magia.


Legge l'intero file e conta il numero di finali di riga? Per arrivare alla fine della riga, non legge sostanzialmente l'intera riga fino a quando non raggiunge la fine? E ciò significherebbe leggere l'intero file, giusto?
detraveller

@detraveller: sì, legge l'intero file, come ho detto. Non lo legge riga per riga, o tutto in una volta, ma legge ogni personaggio e conta quanti di questi personaggi sono caratteri di fine riga.
rici,

7

WC legge semplicemente il file in blocchi di byte grezzi (preferibilmente in multipli della dimensione del blocco naturale del filesystem sottostante su cui si trova il file).
Quindi esegue la scansione del buffer contando i caratteri di fine riga. (Conta anche spazi, tabulazioni, feed di form e altri caratteri speciali, nel caso in cui volessi altre informazioni oltre all'output -l.)

La lettura dal disco è la parte costosa in termini di velocità. La scansione del buffer richiede tempo trascurabile rispetto a quello.

Supponi di avere 90 milioni di righe con in media 100 caratteri per riga.
Sono circa 9.000.000.000 di caratteri o circa 860 MB.
Un PC decente con un'unità SATA-3Gb / s lo farà in meno di 10 secondi. Anche su un filesystem relativamente lento con alcune altre attività in corso contemporaneamente.
Una macchina veloce con un po 'di ottimizzazione delle prestazioni e un filesystem ottimizzato può farlo in meno di 5 secondi, anche senza dover ricorrere a SATA-6G e un'unità SSD.


esegue semplicemente la scansione del buffer contando i caratteri di fine riga ( \n) - "-l, --lines stampa i conteggi della nuova riga \ n \" - estratto dawc.c
Rahul Patil il

@RahulPatil La maggior parte delle implementazioni fa molto di più che contare le nuove righe. Vedi l'esempio menzionato nel commento in alto sopra. Questa è la fonte di wc utilizzata nelle utility core di Linux.
Tonny,

si .. l'ho visto .. ho solo detto perché, domanda su wc -l.. scusa ...
Rahul Patil

3

Benvenuti nel mondo del software libero. Puoi sempre guardare il codice sorgente

Anche se devo ammettere che non sono un programmatore in C, quindi non sono quello che può davvero spiegare il codice per te (e sarei anche io interessato).

Quello che so è che poiché wc non apre il file stesso, ma chiede al sistema operativo di farlo, ciò dipende in gran parte dal sistema operativo e, naturalmente, da come viene archiviato il file. A parte questo, mi aspetto che debbano essere messe in atto le corrette pratiche di programmazione, ad es. Non tentare di leggere l'intero file in una volta, ecc.


Cosa intendi dicendo "non provare a leggere l'intero file in una volta"?
detraveller

Intendo caricare il file in memoria, diciamo, su una singola stringa / matrice. Nella comunità Perl questo si chiama slurping, ed è una soluzione veloce e sporca che è OK quando sai che leggerai poche righe, ma raramente è molto semplice caricare in memoria file davvero enormi contemporaneamente.
Alois Mahdal

1
D'altra parte, puoi leggere, dire, 64 KiB, contare le nuove righe e buttarlo via, ripetere ... In questo modo mangerai al massimo qualcosa di oltre 64 KiB, non importa quanto sia grande il file. (È meno facile quando ti rendi conto che newline può avere 2 byte e quindi dividere tra 2 blocchi; ora è lì che inizia il divertimento)
Alois Mahdal

Non troppo importante, ma: "poiché wc non apre il file stesso, ma chiede al SO di farlo" - non sono sicuro di cosa tu voglia dire, ma dubito che sia corretto. Sta certamente leggendo tutti i personaggi da solo.
Arjan,

2
@Arjan Anche se, per essere davvero corretti: escludendo i sistemi embedded, i programmi difficilmente fanno da soli la lettura da soli, tutto il punto di Kernel e OS è che fa il loro lavoro. In effetti, open (), close (), read () (sia esso Linux, Windows, socket o file) sono tutte chiamate di sistema che i programmi reali non hanno idea del funzionamento interno.
Alois Mahdal
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.