¿Cuál es la mejor manera de contar la cantidad de archivos en un directorio?

11

Si analizar la salida de lses peligroso porque puede romper algunos caracteres extraños (espacios \n, ...), ¿cuál es la mejor manera de saber la cantidad de archivos en un directorio?

Por lo general, confío en findevitar este análisis, pero de manera similar, find mydir | wc -lse romperá por las mismas razones.

Estoy trabajando en Solaris en este momento, pero estoy buscando una respuesta lo más portátil posible en diferentes unidades y diferentes shells.

rahmu
fuente
3
No estoy seguro de que sea un duplicado, ¿me estoy perdiendo algo?
rahmu
1
Esto podría ser un duplicado, pero no de la pregunta indicada. findobtendrá el número de archivos de forma recursiva (úselo -maxdepth 1si no lo desea. find mydir -maxdepth 1 -type f -printf \\n | wc -lDebe manejar los caracteres especiales en el nombre del archivo, ya que nunca se imprimen en primer lugar.
Anthon

Respuestas:

15

¿Qué tal este truco?

find . -maxdepth 1 -exec echo \; | wc -l

Tan portátil como findy wc.

rozcietrzewiacz
fuente
55
Esto no funciona (muestra n+1archivos en mi sistema Debian). Tampoco filtra los archivos normales.
Chris Down
44
Acabo de dar un ejemplo genérico. Funciona, pero cómo funciona depende de cómo adapte el findcomando a sus necesidades específicas. Sí, este incluye todos los directorios, incluido .(que podría ser el motivo por el que ve el resultado como n+1).
rozcietrzewiacz
Me gusta este truco, muy inteligente; ¡Pero me sorprende que no haya una forma sencilla y directa de hacerlo!
rahmu
3
@ChrisDown, el OP no especifica el filtrado de los archivos normales, solicita el número de archivos en un directorio. Para deshacerse del problema n + 1, use find . -maxdepth 1 ! -name . -exec echo \; | wc -l; algunas versiones anteriores de findno tienen -not.
Arcege
3
Tenga en cuenta que -maxdepthno es estándar (una extensión de GNU ahora también es compatible con algunas otras implementaciones).
Stéphane Chazelas
11

Con bash, sin utilidades externas, ni bucles:

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

En ksh, reemplace shopt -s dotglobpor FIGNORE=.?(.). En zsh, reemplácelo setopt glob_dotso elimine la shoptllamada y use files=(*(D)). (O simplemente deje caer la línea si no desea incluir archivos de puntos). Portablemente, si no le importan los archivos de puntos:

set -- *
echo $#

Si desea incluir archivos de puntos:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c
enzotib
fuente
2
El primer ejemplo se imprime 1para un directorio vacío cuando nullglobno está habilitado. En zsh, a=(*(DN));echo ${#a}con el calificador N( nullglob) no se produce un error para un directorio vacío.
nisetama
8
find . ! -name . -prune -print | grep -c /

Debería ser bastante portátil para los sistemas posteriores a los 80.

Eso cuenta todas las entradas del directorio excepto .y ..en el directorio actual.

Para contar archivos en subdirectorios también:

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

(ese debería ser portátil incluso para Unix V6 (1975), ya que no necesita -prune)

Stéphane Chazelas
fuente
Una de las raras respuestas portátiles en esta página, si no la única.
xhienne
Ayer voté por esta respuesta porque descubrí que también funciona bien para directorios distintos al directorio actual ( find dirname ! -name dirname -prune -print). Desde entonces me he estado preguntando si hay alguna razón particular para usar en grep -c /lugar de wc -l(que probablemente se usa más comúnmente para contar).
Anthony Geoghegan el
1
find dirname ! -name dirnameno funciona si hay otros directorios dentro de ese nombre dirname. Es mejor usarlo find dirname/. ! -name .. wc -lcuenta el número de líneas, los nombres de archivo pueden estar formados por varias líneas ya que el carácter de nueva línea es tan válido como cualquier otro en un nombre de archivo.
Stéphane Chazelas
6

Tratar:

ls -b1A | wc -l

El -btendrá caracteres no imprimibles, -Ase mostrarán todos los archivos excepto .e .., y uno por línea (por defecto en una tubería, pero bueno para ser explícito).

Siempre que estemos incluyendo lenguajes de scripting de nivel superior, aquí hay una línea en Python:

python -c 'import os; print len(os.listdir(os.sep))'

O con 'encontrar' completo:

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'
Arcege
fuente
1

Yoc puede usar tal construcción:

I=0; for i in * ; do ((I++)); done ; echo $I

Pero me temo, puede cath error como Argument list too long.en caso de que tenga demasiados archivos en el directorio. Sin embargo, lo probé en el directorio con 10 mil millones de archivos, y funcionó bien.

prisa
fuente
3
Esto tampoco funcionará para archivos ocultos a menos que el shell esté configurado para expandirlos *.
Lekensteyn el
gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley
44
@Rush: este comando nunca debería generar "arg list demasiado larga". Eso sólo sucede con el comando externo (lo que nunca con for.
enzotib
1

¿Has considerado perl, que debería ser relativamente portátil?

Algo como:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";
cjc
fuente
0

Intente esto => Usar ls con -i (para el número de nodo) y -F (agrega el nombre del directorio con las opciones '/').

ls -ilF | egrep -v '/' | wc -l
Saumil
fuente
0

Con una perllínea (reformateada para facilitar la lectura):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

o

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

Puede usar perlfunciones que modifiquen matrices como grepo mapcon la segunda versión. Ver perldoc -f readdirpara un ejemplo usando grep.

cas
fuente
0

La versión más simple que uso todo el tiempo y con la que nunca tuve problemas es: ls -b1 | wc -l

Peter
fuente
Es posible que tenga problemas si el nombre del archivo contiene uno \nu otros caracteres funky (sí, ciertos dispositivos lo permiten).
rahmu
1
Intenté esto explícitamente antes de publicar mi respuesta y no tuve problemas con eso. Utilicé el administrador de archivos nautilus para cambiar el nombre de un archivo que contenga \ n para probar esto.
Peter
Tienes razón, no funciona así. No sé qué hice cuando probé esto primero. Intenté nuevamente y actualicé mi respuesta.
Peter
No, el comando está bien, pero ya existe una solución similar y no se cuentan los archivos ocultos.
xhienne
0

Además de la findrespuesta basada en la propuesta de Stéphane , aquí hay una respuesta compatible con POSIX basada en ls:

ls -qf | tail -n +3 | wc -l
xhienne
fuente