Buscar el número de archivos en un directorio


¿Hay algún método en Linux para calcular el número de archivos en un directorio (es decir, hijos inmediatos) en O(1) (independientemente del número de archivos) sin tener que listar el directorio primero? Si no es O (1), ¿existe una manera razonablemente eficiente?

Estoy buscando una alternativa a ls | wc -l.

Author: Mechanical snail, 2010-09-13

8 answers

Readdir no es tan caro como usted puede pensar. La habilidad es evitar estadificar cada archivo, y (opcionalmente) ordenar la salida de ls.

/bin/ls -1U | wc -l

Evita los alias en su shell, no ordena la salida y enumera 1 archivo por línea (no es estrictamente necesario cuando se canaliza la salida a wc).

La pregunta original se puede reformular como " ¿la estructura de datos de un directorio almacena un recuento del número de entradas?"para que la respuesta es no. No hay una manera más eficiente de contando ficheros que readdir(2) / getdents(2).

 36
Author: Phil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-13 16:49:37

Se puede obtener el número de subdirectorios de un directorio dado sin recorrer toda la lista mediante la estadística (stat(1) o stat(2)) del directorio dado y observando el número de enlaces a ese directorio. Un directorio dado con N directorios secundarios tendrá un número de enlaces de N + 2, un enlace para el ".."entrada de cada subdirectorio, más dos para el "." y ".."entradas del directorio dado.

Sin embargo, no se puede obtener el número de todos los archivos (ya sean archivos regulares o subdirectorios) sin recorrer toda la lista that eso es correcto.

El comando "/bin/ls-1U" no obtendrá todas las entradas. Obtendrá solo aquellas entradas de directorio que no comiencen con el punto (.) caracter. Por ejemplo, no contaría el".perfil " archivo encontrado en muchos directorios login HOME HOME.

Se puede usar el comando "/bin/ls-f" o el comando "/bin/ls-Ua" para evitar la ordenación y obtener todas las entradas.

Tal vez por desgracia para sus propósitos, ya sea el comando "/ bin / ls-f "o el comando" /bin/ls-Ua "también contarán el"." y ".."entradas que están en cada directorio. Tendrá que restar 2 del conteo para evitar contar estas dos entradas, como en lo siguiente:

expr `/bin/ls -f | wc -l` - 2     # Those are back ticks, not single quotes.

La opción format format=single-column (-1) no es necesaria en el comando "/bin/ls-Ua" cuando se canaliza la salida "ls", como en "wc" en este caso. El comando" ls " escribirá automáticamente su salida en una sola columna si la salida no es terminal.

 10
Author: pj_,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-13 18:55:08

La opción -U para ls no está en POSIX, y en OS X ls tiene un significado diferente de GNU ls, que es que hace que -t y -l usen tiempos de creación en lugar de tiempos de modificación. -f está en POSIX como una extensión XSI. El manual de GNU ls describe -f como do not sort, enable -aU, disable -ls --color y -U como do not sort; list entries in directory order.

POSIX describe -f así:

Forzar que cada argumento sea interpretado como un directorio y listar el nombre encontrado en cada ranura. Esta opción se apagar -l, -t, -s, and -r, and shall turn on -a; el orden es el orden en el que aparecen las entradas en el directorio.

Comandos como ls|wc -l dan un resultado incorrecto cuando los nombres de archivo contienen nuevas líneas.

En zsh, puedes hacer algo como esto:

a=(*(DN));echo ${#a}

D (glob_dots) incluye archivos cuyo nombre comienza con un punto y N (null_glob) hace que el comando no genere un error en un directorio vacío.

O lo mismo en bash:

shopt -s dotglob nullglob;a=(*);echo ${#a[@]}

Si IFS contiene dígitos ASCII, agregue comillas dobles alrededor de ${#a[@]}. Agregue shopt -u failglob para asegurarse de que failglob no esté configurado.

Una opción portátil es usar find:

find . ! -name . -prune|grep -c /

grep -c / puede ser reemplazado por wc -l si los nombres de archivo no contienen nuevas líneas. ! -name . -prune es una alternativa portátil a -mindepth 1 -maxdepth 1.

O aquí hay otra alternativa que generalmente no incluye archivos cuyo nombre comienza con un punto:

set -- *;[ -e "$1" ]&&echo "$#"

Sin embargo, el comando anterior incluye archivos cuyo nombre comienza con un punto cuando se establece una opción como dotglob en bash o glob_dots en zsh. Cuando * no coincide con ningún archivo, el comando produce un error en zsh con la configuración predeterminada.

 3
Author: user4669748,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-12 00:27:37

Usé este comando..funciona como un encanto..sólo para cambiar el maxdepth..eso es subdirectorios

find * -maxdepth 0 -type d -exec sh -c "echo -n {} ' ' ; ls -lR {} | wc -l" \;
 2
Author: user2991011,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-11 18:35:45

Creo que puedes tener más control sobre esto usando find:

find <path> -maxdepth 1 -type f -printf "." | wc -c
  • find -maxdepth 1 no profundizará en la jerarquía de archivos.
  • -type f permite filtrar solo archivos. Del mismo modo, puede usar -type d para directorios.
  • -printf "." imprime un punto por cada coincidencia.
  • wc -c cuenta los caracteres, por lo que cuenta los puntos creados por el print... lo que significa contar cuántos archivos existen en la ruta dada.
 2
Author: fedorqui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-02 10:23:47

Hasta donde yo sé, no hay mejor alternativa. Esta información podría estar fuera del tema de esta pregunta y es posible que ya sepa que bajo Linux (en general bajo Unix) los directorios son solo archivos especiales que contienen la lista de otros archivos (entiendo que los detalles exactos dependerán del sistema de archivos específico, pero esta es la idea general). Y no hay llamada para encontrar el número total de entradas sin recorrer toda la lista. Por favor, corrígeme si me equivoco.

 1
Author: taskinoor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-13 16:03:36

Para el número de todos los archivos en un directorio actual intente esto:

ls -lR * | wc -l
 0
Author: chry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-02 07:15:09

Use ls -1 / wc-l

 -1
Author: Venkataramesh Kommoju,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-14 11:30:20