script - ¿Hay un comando bash que cuenta los archivos?
scripts bash ejemplos (8)
¿Hay un comando bash que cuenta la cantidad de archivos que coinciden con un patrón?
Por ejemplo, quiero obtener el recuento de todos los archivos en un directorio que coincida con este patrón: log*
Aquí está mi único trazador de líneas para esto.
file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)
Este simple one-liner debería funcionar en cualquier caparazón, no solo en bash:
ls -1q log* | wc -l
ls -1q le dará una línea por archivo, incluso si contienen espacios en blanco o caracteres especiales como líneas nuevas.
La salida se canaliza a wc -l, que cuenta el número de líneas.
La respuesta aceptada para esta pregunta es incorrecta, pero tengo baja repetición, por lo que no puedo agregar un comentario.
La respuesta correcta a esta pregunta es dada por Mat:
shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}
El problema con la respuesta aceptada es que wc -l cuenta el número de caracteres de nueva línea y los cuenta incluso si imprimen en el terminal como ''?'' en la salida de ''ls -l''. Esto significa que la respuesta aceptada FALLAS cuando un nombre de archivo contiene un carácter de nueva línea. He probado el comando sugerido:
ls -l log* | wc -l
e informa erróneamente un valor de 2 incluso si solo hay 1 archivo que coincida con el patrón cuyo nombre contiene un carácter de nueva línea. Por ejemplo:
touch log$''/n''def
ls log* -l | wc -l
Muchas respuestas aquí, pero algunas no tienen en cuenta
- nombres de archivo con espacios, líneas nuevas o caracteres de control en ellos
- nombres de archivo que comienzan con guiones (imagine un archivo llamado
-l
) - directorios vacíos (es decir, el resultado es 0)
- directorios extremadamente grandes (enumerarlos todos podría agotar la memoria)
Aquí hay una solución que maneja todos ellos:
ls 2>/dev/null -Ub1 -- log* | wc -l
Explicación:
-
-U
hace quels
no ordene las entradas, lo que significa que no necesita cargar toda la lista de directorios en la memoria -
-b
imprime escapes estilo C para caracteres no gráficos, lo que hace que las líneas nuevas se impriman como/n
. -
2>/dev/null
redirige stderr, de modo que si hay 0 archivos de registro, ignore el mensaje de error. (Tenga en cuenta queshopt -s nullglob
haría quels
shopt -s nullglob
todo el directorio de trabajo en su lugar). -
wc -l
consume la lista de directorios a medida que se genera, por lo que la salida dels
nunca está en la memoria en ningún momento. -
--
Los nombres de los archivos se separan del comando usando--
para no entenderse como argumentos parals
(en caso de que se elimine ellog*
)
El shell ampliará el log*
a la lista completa de archivos, lo que puede agotar la memoria si se trata de una gran cantidad de archivos, por lo que ejecutarlo a través de grep es mejor:
ls -Ub1 | grep ^log | wc -l
Este último maneja directorios extremadamente grandes de archivos sin utilizar mucha memoria (aunque usa una subcaja).
Puede hacer esto de forma segura (es decir, no será molestado por archivos con espacios o /n
en su nombre) con bash:
$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
$ shopt -u nullglob
nullglob
habilitar nullglob
para que no obtenga literal *.log
en la array $logfiles
si no hay ningún archivo coincidente.
Si tiene muchos archivos y no desea utilizar la elegante shopt -s nullglob
and bash array, puede usar find y demás siempre que no imprima el nombre del archivo (que podría contener nuevas líneas). )
find -maxdepth 1 -name "log*" -not -name ".*" -printf ''%i/n'' | wc -l
Esto encontrará todos los archivos que coincidan con el registro * y que no comiencen con .*
- El "no nombre. *" Se redunde, pero es importante tener en cuenta que el valor predeterminado para "ls" es no mostrar archivos de puntos, pero el valor predeterminado para find es incluirlos.
Esta es una respuesta correcta y maneja cualquier tipo de nombre de archivo que pueda arrojar, ya que el nombre del archivo nunca se pasa entre los comandos.
¡Pero la respuesta de shopt nullglob
es la mejor respuesta!
Prueba esto:
echo *.log | wc -w
O para una búsqueda recursiva:
find . -type f -name ''*.log'' | wc -l
wc -w
cuenta el número de palabras en la salida (bash ampliará *.log
como una lista de archivos separados por espacios que coincidan con ese patrón), mientras que wc -l
contará el número de líneas ( find
imprime un resultado por línea).
Actualización : para una búsqueda no recursiva, haga esto:
find . -maxdepth 1 -type f -name ''*.log'' | wc -l
Esto sorteará el problema de espacio mencionado por lanzz.
ls -1 log* | wc -l
Lo que significa que debe listar un archivo por línea y luego canalizarlo al comando de conteo de palabras con el cambio de parámetro a líneas de conteo.