¿Cómo se forma recursiva lista de todos los directorios en una ubicación, la amplitud de primera?
Pregunta
La amplitud primero de la lista es importante, aquí.También, la limitación de la profundidad buscada sería bueno.
$ find . -type d
/foo
/foo/subfoo
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub
/bar
/bar/subbar
$ find . -type d -depth
/foo/subfoo/subsub/subsubsub
/foo/subfoo/subsub
/foo/subfoo
/foo
/bar/subbar
/bar
$ < what goes here? >
/foo
/bar
/foo/subfoo
/bar/subbar
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub
Me gustaría hacerlo con una fiesta de una línea, si es posible.Si hubo un javascript-shell, me imagino algo como
bash("find . -type d").sort( function (x) x.findall(/\//g).length; )
Solución
El comando find
apoya la opción -printf
que reconoce una gran cantidad de marcadores de posición.
Un tal marcador de posición es %d
que hace que la profundidad de la trayectoria dada, en relación con donde comenzó find
.
Por lo tanto se puede utilizar después de sencilla de una sola línea:
find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-
Es muy sencillo, y no depende de herramientas pesadas como perl
.
¿Cómo funciona?:
- internamente lista de archivos, genera cada uno representa como una línea de dos campos
- el primer campo contiene la profundidad, que se utiliza para (inversa) de clasificación numérica, y luego se corta distancia
- resultante es la lista de archivos simple, un archivo por línea, en lo más profundo-primer orden
Otros consejos
Si desea hacer uso de herramientas estándar, la siguiente línea de trabajo:
find . -type d | perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2
Es decir,
- encontrar e imprimir todos los directorios aquí, en la profundidad de primer orden
- contar el número de barras en cada directorio y escriba la ruta de acceso
- ordenar por profundidad (es decir, número de barras)
- la extracción de la ruta.
Para limitar la profundidad, agregar el-maxdepth argumento para el comando buscar.
Si desea que los directorios de la lista en el mismo orden que encontrar una salida, el uso de "sort-n -s" en lugar de "sort-n";la "-s" de la bandera estabiliza el tipo (es decir, conservas de entrada de orden entre los elementos que se comparan igualmente).
No creo que podría hacerlo utilizando una función de los servicios públicos, ya que cuando se atraviesa una jerarquía de directorios que casi siempre se desea una búsqueda en profundidad, de arriba hacia abajo o de abajo hacia arriba. Aquí hay un script en Python que le dará una búsqueda en amplitud:
import os, sys
rootdir = sys.argv[1]
queue = [rootdir]
while queue:
file = queue.pop(0)
print(file)
if os.path.isdir(file):
queue.extend(os.path.join(file,x) for x in os.listdir(file))
Editar
- Uso
os.path
-módulo en lugar deos.stat
-función ystat
-módulo. - Uso
list.pop
ylist.extend
en lugar de operadoresdel
y+=
.
Mi sensación es que esta es una solución mejor que anteriormente citados. Se trata de grep y tal y un lazo, pero me parece que funciona muy bien, especialmente para los casos en los que desee cosas búfer de línea y no la plena encontrar tamponada.
Es más intensivo de los recursos debido a:
- Las porciones de la bifurcación
- Un montón de hallazgos
- Cada directorio antes de la profundidad actual es golpeado por encontrar tantas veces como hay profundidad total de la estructura de archivos (esto no debería ser un problema si usted tiene prácticamente cualquier cantidad de ram ...)
Esto es bueno porque:
- Utiliza bash y herramientas GNU básicos
- Se puede romperse cuando lo desee (como se ve lo que estabas buscando mosca por)
- Se trabaja por línea y no por encontrar, por lo que los comandos subsiguientes no tiene que esperar a que un hallazgo y una especie
- El fármaco actúa basa en la separación real del sistema de archivos, por lo que si usted tiene un directorio con una barra en el mismo, que no se enumeran más profunda de lo que es; si tiene un separador de ruta diferente configurado, todavía están bien.
#!/bin/bash depth=0 while find -mindepth $depth -maxdepth $depth | grep '.' do depth=$((depth + 1)) done
También puede encajar en una línea bastante facilidad (?):
depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done
Pero yo prefiero más pequeños scripts escribiendo ...
Puede utilizar comandos encontrar, find / ruta / a / d de tipo dir Así que a continuación ejemplo lista de directorios en el directorio actual:
find . -type d
He intentado encontrar una manera de hacer esto con find
pero no parecen tener nada como una opción -breadth
. Short de escribir un parche para que, intente lo siguiente encantamiento shell (por bash):
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
while test -n "$LIST"; do
for F in $LIST; do
echo $F;
test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
done;
LIST=$NLIST;
NLIST="";
done
En cierto modo me encontré con este accidente, así que no sé si funciona en general (que estaba probando sólo en la estructura de directorios específica que estabas preguntando acerca)
Si desea limitar la profundidad, poner una variable de contador en el bucle exterior, al igual que (También estoy añadiendo comentarios a éste):
# initialize the list of subdirectories being processed
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
# initialize the depth counter to 0
let i=0;
# as long as there are more subdirectories to process and we haven't hit the max depth
while test "$i" -lt 2 -a -n "$LIST"; do
# increment the depth counter
let i++;
# for each subdirectory in the current list
for F in $LIST; do
# print it
echo $F;
# double-check that it is indeed a directory, and if so
# append its contents to the list for the next level
test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
done;
# set the current list equal to the next level's list
LIST=$NLIST;
# clear the next level's list
NLIST="";
done
(reemplazar el 2 en -lt 2
con la profundidad)
Básicamente esto implementa el algoritmo de búsqueda en anchura estándar utilizando $LIST
y $NLIST
como una cola de nombres de directorios. Aquí está el último enfoque como una sola línea para una fácil de copiar y pegar:
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)"; let i=0; while test "$i" -lt 2 -a -n "$LIST"; do let i++; for F in $LIST; do echo $F; test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)"; done; LIST=$NLIST; NLIST=""; done
Sin el merecido el pedido: encontrar -maxdepth de tipo d
Para obtener el merecido pedido, que tiene que hacer la recursión mismo, con este pequeño shellscript:
#!/bin/bash
r ()
{
let level=$3+1
if [ $level -gt $4 ]; then return 0; fi
cd "$1"
for d in *; do
if [ -d "$d" ]; then
echo $2/$d
fi;
done
for d in *; do
if [ -d "$d" ]; then
(r "$d" "$2/$d" $level $4)
fi;
done
}
r "$1" "$1" 0 "$2"
A continuación, puede llamar a este script con el directorio base de parámetros y profundidad.
Aquí hay una manera posible, utilizando hallazgo. No he probado a fondo, así que el usuario tenga cuidado ...
depth=0
output=$(find . -mindepth $depth -maxdepth $depth -type d | sort);
until [[ ${#output} -eq 0 ]]; do
echo "$output"
let depth=$depth+1
output=$(find . -mindepth $depth -maxdepth $depth -type d | sort)
done
Algo como esto:
find . -type d |
perl -lne'push @_, $_;
print join $/,
sort {
length $a <=> length $b ||
$a cmp $b
} @_ if eof'