¿Cómo funciona `wc -l`?

11

Tengo que leer un archivo grande y antes de comenzar a leerlo, necesito saber el número total de líneas en el archivo (que están en millones).

He implementado muchas soluciones y he encontrado una. Pero durante mi búsqueda estaba pensando en ver cómo wc -lfunciona. No pude encontrar nada en Google.

Aunque he encontrado una solución a mi problema, todavía me gustaría saber cómo wc -lfunciona, ¡ya que puede calcular el número de líneas de un archivo con 92 millones de líneas en unos segundos!

¿Cómo?

detraveller
fuente

Respuestas:

20

Lee todo el archivo y cuenta el número de finales de línea. Contar terminaciones de línea es realmente barato; la mayor parte del tiempo dedicado es leer el archivo. Si el archivo está (principalmente) en la memoria caché del búfer, también será barato. De lo contrario, dependerá de la velocidad de almacenamiento de su archivo.

En otras palabras, no hay magia.

rici
fuente
¿Lee todo el archivo y cuenta el número de terminaciones de línea? Para llegar al final de la línea, ¿no lee básicamente toda la línea hasta que llega al final? Y eso significaría que lee todo el archivo, ¿verdad?
Detraveller
@detraveller: sí, lee todo el archivo, como dije. No lo lee línea por línea, o todo a la vez, pero lee cada carácter y cuenta cuántos de esos caracteres son caracteres de final de línea.
rici
7

WC solo lee el archivo en bloques de bytes sin procesar (preferiblemente en múltiplos del tamaño de bloque natural del sistema de archivos subyacente en el que se encuentra el archivo).
Luego solo escanea a través del búfer contando los caracteres de fin de línea. (También cuenta espacios, pestañas, feeds de formularios y otros caracteres especiales, en caso de que desee otra información que no sea la salida -l).

Leer desde el disco es la parte costosa en términos de velocidad. El escaneo del búfer lleva un tiempo descuidado en comparación con eso.

Supongamos que tiene 90 millones de líneas con un promedio de 100 caracteres por línea.
Eso es alrededor de 9.000.000.000 de caracteres o alrededor de 860 MB.
Una PC decente con una unidad SATA-3Gb / s lo hará en menos de 10 segundos. Incluso en un sistema de archivos relativamente lento con alguna otra actividad al mismo tiempo.
Una máquina rápida con algunos ajustes de rendimiento y un sistema de archivos optimizado puede hacerlo en menos de 5 segundos, incluso sin tener que recurrir a SATA-6G y una unidad SSD.

Tonny
fuente
simplemente escanea a través del búfer contando los caracteres de fin de línea ( \n) - "-l, --lines imprime los recuentos de nueva línea \ n \" - extraído dewc.c
Rahul Patil
@RahulPatil La mayoría de las implementaciones hacen mucho más que solo contar nuevas líneas. Vea el ejemplo mencionado en el comentario superior anterior. Esa es la fuente de wc como se usa en las utilidades principales de Linux.
Tonny
sí ... lo he visto ... solo lo menciono porque, pregunta sobre wc -l... lo siento ...
Rahul Patil
3

Bienvenido al mundo del software libre. Siempre puedes mirar el código fuente

Aunque debo admitir que no soy un programador en C, entonces no soy el que realmente puede explicarte el código (y yo mismo estaría interesado).

Lo que sé es que, dado que wc no abre el archivo en sí, sino que le pide al sistema operativo que lo haga, esto depende en gran medida del sistema operativo y, por supuesto, de cómo se almacena el archivo. Aparte de eso, esperaría que las prácticas de programación correctas deben estar en su lugar, por ejemplo, no tratar de leer el archivo completo de una vez, etc.

Alois Mahdal
fuente
¿Qué quieres decir con "no intentar leer todo el archivo a la vez"?
Detraveller
Me refiero a cargar el archivo en la memoria, por ejemplo, en una sola cadena / matriz. En la comunidad de Perl, esto se llama sorber, y es una solución rápida y sucia que está bien cuando sabes que leerás algunas líneas, pero alimentar un archivo realmente enorme en la memoria a la vez rara vez es una buena idea.
Alois Mahdal
1
Por otro lado, puede leer, digamos, 64 KiB, contar líneas nuevas y tirarlo a la basura, repetir ... De esa manera comerá algo más de 64 KiB como máximo, sin importar cuán grande sea el archivo. (Es menos fácil cuando te das cuenta de que la nueva línea puede tener 2 bytes y, por lo tanto, dividirse entre 2 fragmentos; ahora es donde comienza la diversión)
Alois Mahdal
No es demasiado importante, pero: "dado que wc no abre el archivo en sí, pero le pide al sistema operativo que lo haga" , no estoy seguro de qué quiere decir con eso, pero dudo que esto sea correcto. Ciertamente está leyendo todos los personajes por sí mismo.
Arjan
2
@Arjan Aunque, para ser realmente correctos: excluyendo los sistemas embebidos, los programas apenas hacen la lectura por sí mismos, el punto central de Kernel y OS es que hace el trabajo por ellos. De hecho, open (), close (), read () (ya sea Linux, Windows, socket o archivo) son todas llamadas de sistema que los programas reales no tienen idea del funcionamiento interno.
Alois Mahdal