Necesito un script que cuente los archivos en un directorio (y sub). Tomé el guión siguiente y lo cambié según mis necesidades.
Funciona como debería, excepto en las carpetas con caracteres de espacio. Estoy bastante seguro de que me faltan comillas en alguna parte, pero todavía no puedo entenderlo.
Información adicional
- Linux 2.6.22.19-0.4-predeterminado (este servidor ya no se encuentra en un entorno productivo).
- GNU encuentra la versión 4.2.31
- No puedo cambiar el nombre de los directorios.
Ejemplo de estructura de directorio
.
..
01_infos
02_sent
03_inbox
04_public and private
197.
145.
329.
13.
Guion
#!/bin/bash
# Write a script that will count the number of files in each of your subdirectories.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
START=$HOME
# change your directory to command line if passed
# otherwise use home directory
[ $# -eq 1 ] && START=$1 || :
if [ ! -d $START ]
then
echo "$START not a directory!"
exit 1
fi
# use find command to get all subdirs name in DIRS variable
DIRS=$(find "$START" -type d)
# loop thought each dir to get the number of files in each of subdir
for d in $DIRS
do
echo "$d directory has $(find "$d" -maxdepth 1 -regex '.*\.' -type f | wc -l) files" || :
done
producción
./01_infos directory has 1 files
./02_sent directory has 9 files
./03_inbox has 4 files
find: ./04_public: No such file or directory
Respuesta1
Te faltan algunas comillas dobles (Siempre coloque comillas dobles alrededor de las sustituciones de variables $foo
y de comandos.$(foo)
, a menos que sepa por qué puede omitirlos de manera segura y necesita omitirlos). Pero ese no es todo el problema.
if [ ! -d $START ]
debiera ser if [ ! -d "$START" ]
.
DIRS=$(find "$START" -type d)
En este punto, DIRS
contiene el nombre del directorio de inicio y sus subdirectorios de forma recursiva, con nuevas líneas en el medio. Entonces, si tiene un nombre de directorio que contiene una nueva línea, está perdido: es imposible saber qué nuevas líneas provienen de un nombre de directorio y cuáles eran separadores. Si sabe que no hay nuevas líneas en los nombres de los archivos, puede analizar el resultado de find
, pero ¿cómo lo sabe?
Por cierto, está bien no tener comillas dobles aquí $(…)
porque se trata de asignaciones de variables y las sustituciones en las asignaciones están implícitamente protegidas. Sin embargo, tenga en cuenta que no está protegido de manera similar. Es mejor utilizar comillas a menos que domines los scripts de shell y también lo sean todas las personas que mantendrán tu script.export DIRS=$(…)
for d in $DIRS
Aquí es donde pierdes: quieres dividir $DIRS
en palabras, por lo que no puedes poner comillas dobles, pero necesitas comillas dobles porque $DIRS
tiene todos los elementos concatenados y los nombres de archivos dentro de espacios serían separadores si los dejas sin comillas.
Por lo general, cuando usas find
, debes hacer que invoque el comando de procesamiento, con la -exec
opción. A menos que tenga controles estrictos sobre los nombres de los archivos, no analice el resultado de find
: es ambiguo.
find "$START" -type d -exec sh -c '
echo "$0 directory has $(find "$0" -maxdepth 1 -regex ".*\\." -type f -printf \\n | wc -l) files whose name ends with ."
' {} \;
Tenga en cuenta nuevamente en el comando incrustado find
que si analiza la salida de find
, su recuento se cancelará si algún nombre de archivo contiene una nueva línea.
Respuesta2
¿Qué tal solo esto?
find . -type d -exec sh -c '/bin/echo -n "{}"; find "{}" -maxdepth 1 -regex ".*\." -type f | wc -l; ' \;
El resultado no es tan dulce, pero no requiere un script y funciona para directorios con espacios, así como otros caracteres no alfanuméricos.
Respuesta3
Tienes un error clásico al citar. Arregle el bucle for para que se vea así:
for d in "$DIRS"
Alternativamente, puede alimentar su find
salida directamente, por ejemplo:
find "$START" -type d | while read d
do # and so on...
Además, el || :
bit es completamente redundante, ya que echo
siempre tiene un valor de retorno de 0.