¿Cómo enumera el número de líneas de cada archivo en un directorio en formato legible por humanos?

41

Tengo una lista de directorios y subdirectorios que contienen grandes archivos csv. Hay alrededor de 500 millones de líneas en estos archivos, cada uno es un registro. Me gustaría saber

  1. Cuántas líneas hay en cada archivo.
  2. Cuántas líneas hay en el directorio.
  3. Cuantas líneas en total

Lo más importante, necesito esto en 'formato legible por humanos', por ejemplo. 12,345,678 en lugar de 12345678

Sería bueno aprender cómo hacer esto de 3 maneras. Herramientas simples de vainilla bash, awk, etc., y perl (o python).

Hexatónico
fuente

Respuestas:

57

Cuántas líneas hay en cada archivo.

Uso wc, originalmente para el recuento de palabras, creo, pero puede hacer líneas, palabras, caracteres, bytes y la longitud de línea más larga. La -lopción le dice que cuente líneas.

wc -l <filename>

Esto generará el número de líneas en:

$ wc -l /dir/file.txt
32724 /dir/file.txt

También puede canalizar datos a wc:

$ cat /dir/file.txt | wc -l
32724
$ curl google.com --silent | wc -l
63

Cuántas líneas hay en el directorio.

Tratar:

find . -name '*.pl' | xargs wc -l

otra línea:

( find ./ -name '*.pl' -print0 | xargs -0 cat ) | wc -l

Por cierto, el wccomando cuenta nuevos códigos de líneas, no líneas. Cuando la última línea del archivo no termina con un nuevo código de línea, esto no contará.

Puede usar grep -c ^, ejemplo completo:

#this example prints line count for all found files
total=0
find /path -type f -name "*.php" | while read FILE; do
     #you see use grep instead wc ! for properly counting
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count #in bash, you can convert this for another shell
done
echo TOTAL LINES COUNTED:  $total

Cuantas líneas en total

No estoy seguro de haber entendido que solicita correctamente. por ejemplo, esto generará resultados en el siguiente formato, mostrando el número de líneas para cada archivo:

# wc -l `find /path/to/directory/ -type f`
 103 /dir/a.php
 378 /dir/b/c.xml
 132 /dir/d/e.xml
 613 total

Alternativamente, puede resultar útil generar solo el número total de caracteres de línea nuevos sin el archivo por conteo de archivos al siguiente comando:

# find /path/to/directory/ -type f -exec wc -l {} \; | awk '{total += $1} END{print total}'
 613

Lo más importante, necesito esto en 'formato legible por humanos', por ejemplo. 12,345,678 en lugar de 12345678

Bash tiene una función printf incorporada:

printf "%0.2f\n" $T

Como siempre, hay muchos métodos diferentes que podrían usarse para lograr los mismos resultados mencionados aquí.

malyy
fuente
Por cierto, ¿cómo uso printf en tus ejemplos? Traté de canalizarlo desde wc -l, pero no funcionó.
Hexatónico
intente> encontrar. -nombre '* .pl' | xargs wc -l | awk '{printf ("% 0.2f", $ 1)} {print $ 2}' cambia la salida de 'printf' para sus necesidades
malyy
Sin embargo, esto no agrega comas al número para que sea más legible para los humanos. Simplemente agrega ceros al final.
Hexatónico
echo 1000000000000 | xargs printf "% 'd \ n" 1,000,000,000,000
Hexatónico
1
@Hexatonic printfno lee sus argumentos stdin, sino más bien desde la línea de comandos (compara tuberías con echotuberías versus cat; catlee de stdin, echono lo hace). En su lugar, use printf "$(find ... | xargs ...)"para suministrar la salida como argumentos para printf.
BallpointBen
13

En muchos casos, combinar el wccomando y el comodín *puede ser suficiente.
Si todos sus archivos están en un solo directorio, puede llamar a:

wc -l src/*

También puede enumerar varios archivos y directorios:

wc -l file.txt readme src/* include/*

Este comando mostrará una lista de los archivos y su número de líneas.
La última línea será la suma de las líneas de todos los archivos.


Para contar todos los archivos en un directorio de forma recursiva:

Primero, habilite globstar agregando shopt -s globstara su .bash_profile. El soporte para globstar requiere Bash ≥ 4.x que se puede instalar brew install bashsi es necesario. Puedes consultar tu versión con bash --version.

Entonces corre:

wc -l **/*

Tenga en cuenta que esta salida será incorrecta si globstar no está habilitado.

Thomio
fuente
Y para contar archivos en el directorio actual de forma recursiva:wc -l **/*
Taylor Edmiston
@TaylorEdmiston Para mí (en Mac) que solo cuenta los archivos exactamente un directorio hacia abajo. Omite los archivos en el directorio actual, y para cualquier caso que tenga más de un directorio de profundidad, advierte que es un directorio: " wc: parent_dir/child_dir: read: Is a directory"
M. Justin
@Thomio Requiere que globstar esté habilitado. En macOS, creo que está desactivado de fábrica. Acabo de enviar una edición a su respuesta que agrega el comando y cómo habilitar globstar.
Taylor Edmiston
2

Este comando dará una lista de código de líneas en cada directorio:

find . -name '*.*' -type f | xargs wc -l
Suresh.A
fuente
2

un poco tarde para el juego, pero recibí un montón de errores de argumento con lo anterior debido al tamaño del directorio. Esto funcionó para mí:

for i in $(find . -type f); do wc -l $i; done >> /home/counts.txt

Ron Paulfan
fuente
0

catcombinaría los archivos en uno y generaría todo para stdout, puede hacer wc -leso para un recuento total de líneas de archivos en un directorio:

cat /path/to/directory/* | wc -l
picmate 涅
fuente
0

Solo aumentaré la respuesta de @malyy para lo siguiente (demasiado grande para un comentario):

Cuantas líneas en total

Muchas respuestas están utilizando la wcopción de archivo de línea de comandos con xargs. El problema con esto es que xargs se limita a un tamaño dependiente de la plataforma bastante pequeño.

Además, hay una diferencia entre BSD (macOS) y GNU (linux / homebrew) wc.

El GNU One es ideal porque puede leer la lista de archivos de un archivo en lugar de argumentos ( --files0).

Si está en Mac y tiene homebrew, debe hacer lo siguiente:

find . -name "*.pl" -print0 | gwc -l --files0=-

Observe el gwc en lugar de wc .

Adam Gent
fuente