Pregunta ¿Hay un comando bash que cuenta los archivos?


¿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*


75
2017-07-03 08:35


origen


Respuestas:


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.


101
2017-07-03 08:41



Puede hacer esto de manera 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

Necesitas habilitar nullglob para que no obtenga el literal *.log en el $logfiles  formación si ningún archivo coincide


33
2017-07-03 08:43



Prueba esto:

echo *.log | wc -w


30
2017-07-03 08:41



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 causas ls para no ordenar las entradas, lo que significa que no es necesario 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 de manera crucial \n.
  • 2>/dev/null redirects stderr para que si hay 0 archivos de registro, ignore el mensaje de error. (Tenga en cuenta que shopt -s nullglob causaría ls para enumerar 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 de ls nunca está en la memoria en ningún momento.
  • -- Los nombres de archivo están separados del comando usando -- para no ser entendido como argumentos para ls (en caso log* es removido)

La cáscara será expandir log* a la lista completa de archivos, 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).


28
2017-11-24 11:01



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

5
2017-10-30 06:11



Si tiene muchos archivos y no quiere usar el elegante shopt -s nullglob y la solución bash array, puede usar find y demás siempre que no imprima el nombre del archivo (que podría contener líneas nuevas).

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 el shopt nullglob la respuesta es la mejor respuesta!


4
2017-08-22 19:16



Aquí está mi único trazador de líneas para esto.

 file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)

2
2017-11-04 19:48



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.


1
2017-07-03 20:17