¿Cómo se forma recursiva lista de todos los directorios en una ubicación, la amplitud de primera?

StackOverflow https://stackoverflow.com/questions/539583

  •  22-08-2019
  •  | 
  •  

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; )
¿Fue útil?

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,

  1. encontrar e imprimir todos los directorios aquí, en la profundidad de primer orden
  2. contar el número de barras en cada directorio y escriba la ruta de acceso
  3. ordenar por profundidad (es decir, número de barras)
  4. 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

  1. Uso os.path-módulo en lugar de os.stat-función y stat-módulo.
  2. Uso list.pop y list.extend en lugar de operadores del 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'
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top