Domanda

L'elenco completo è importante, qui.Inoltre, limitare la profondità della ricerca sarebbe carino.

$ 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

Mi piacerebbe farlo usando una battuta bash, se possibile.Se ci fosse una shell javascript, immagino qualcosa del genere

bash("find . -type d").sort( function (x) x.findall(/\//g).length; )
È stato utile?

Soluzione

Il comando find supporta l'opzione -printf che riconosce un sacco di segnaposto.

Un tale segnaposto è %d che rende la profondità di percorso determinato, relativamente al luogo dove find iniziato.

Pertanto è possibile utilizzare seguente semplice linea:

find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-

E 'molto semplice, e non dipende da utensili pesanti come perl.

Come funziona:

  • genera internamente elenco di file, ogni reso come una linea a due campi
  • il primo campo contiene la profondità, che viene utilizzato per (reverse) ordinamento numerico, e quindi tagliare via
  • risultante è semplice elenco dei file, un file per riga, nel più profondo-primo ordine

Altri suggerimenti

Se si vuole farlo utilizzando strumenti standard, il seguente gasdotto dovrebbe funzionare:

find . -type d | perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2

Questo significa che

  1. trovare e stampare tutte le directory qui in modo approfondito primo ordine
  2. contare il numero di barre in ogni directory e anteporre al percorso
  3. ordina in profondità (cioè, il numero di barre)
  4. estratto solo il percorso.

Per limitare la profondità trovata, aggiungere l'argomento -maxdepth al comando find.

Se si desidera che le directory elencate nello stesso ordine che trovano l'uscita di loro, utilizzano "sort -n -s" invece di "sort -n"; il "-s" bandiera stabilizza il tipo (cioè, conserva ordine di input tra gli oggetti che confrontano ugualmente).

Non credo che si potrebbe fare utilizzando built-in programmi di utilità, dal momento che quando si attraversa una gerarchia di directory si vuole quasi sempre una ricerca in profondità, sia top-down o bottom-up. Ecco uno script Python che vi darà una ricerca in ampiezza:

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))

Modifica

  1. Uso os.path modulo anziché os.stat-funzione e stat modulo.
  2. Uso list.pop e list.extend invece di operatori del e +=.

La mia sensazione è che questa sia una soluzione migliore di quelle menzionate in precedenza.Implica grep e simili e un ciclo, ma trovo che funzioni molto bene, in particolare per i casi in cui si desidera che le cose vengano bufferizzate nella riga e non nel buffer di ricerca completo.

Richiede più risorse a causa di:

  • Molte biforcazioni
  • Molti reperti
  • Ogni directory prima della profondità corrente viene colpita da find tante volte quanto è la profondità totale della struttura del file (questo non dovrebbe essere un problema se hai praticamente qualsiasi quantità di RAM...)

Questo è positivo perché:

  • Utilizza bash e strumenti gnu di base
  • Può essere rotto quando vuoi (come se vedessi volare quello che stavi cercando)
  • Funziona per riga e non per ricerca, quindi i comandi successivi non devono attendere una ricerca e un ordinamento
  • Funziona in base all'effettiva separazione del file system, quindi se hai una directory con una barra, non verrà elencata più in profondità di quanto sia;se hai configurato un separatore di percorso diverso, stai comunque bene.
#!/bin/bash 
depth=0

while find -mindepth $depth -maxdepth $depth | grep '.'
do
    depth=$((depth + 1))
done

Puoi anche adattarlo su una riga abbastanza (?) facilmente:

depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done

Ma preferisco i piccoli script rispetto alla digitazione...

È possibile utilizzare Trova il comando, find / path / to / dir tipo d Così sotto esempio lista di directory nella directory corrente:

find . -type d

Ho cercato di trovare un modo per fare questo con find ma non sembrano avere qualcosa di simile un'opzione -breadth. Breve di scrivere una patch per esso, provare quanto segue incantesimo della shell (per 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

I sorta di imbatterci in questo accidentalmente in modo da non so se funziona in generale (stavo testando solo sulla struttura di directory specifica che stavi chiedendo circa)

Se si vuole limitare la profondità, mettere una variabile contatore nel ciclo esterno, in questo modo (sto anche l'aggiunta di commenti a questo):

# 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

(sostituire il 2 in -lt 2 con la profondità)

In pratica questo implementa l'algoritmo di ricerca in ampiezza standard utilizzando $LIST e $NLIST come una coda di nomi di directory. Ecco il secondo approccio come un one-liner per un facile copia-e-incolla:

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

Senza l'ordine meritato:     trovare -maxdepth tipo d

Per ottenere l'ordinamento meritato, quello che dovete fare la ricorsione da soli, con questo piccolo 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"

Poi si può chiamare lo script con directory parametri di base e la profondità.

Ecco un modo possibile, utilizzando find. Non ho accuratamente testato, così l'utente attenzione ...

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

Qualcosa di simile a questo:

find . -type d | 
  perl -lne'push @_, $_;
    print join $/,
      sort { 
        length $a <=> length $b || 
          $a cmp $b 
        } @_ if eof'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top