La liste étendue est ici importante. Aussi, limiter la profondeur recherchée serait sympa.
$ 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
Je voudrais le faire en utilisant une doublure bash, si possible. S'il y avait un javascript-Shell, j'imagine quelque chose comme
bash("find . -type d").sort( function (x) x.findall(/\//g).length; )
La commande find
prend en charge -printf
option qui reconnaît de nombreux espaces réservés.
Un de ces espaces réservés est %d
qui rend la profondeur du chemin donné, par rapport à l'endroit où find
a commencé.
Par conséquent, vous pouvez utiliser un simple revêtement simple:
find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-
C'est assez simple et ne dépend pas d'outils lourds comme Perl
.
Comment ça fonctionne:
Si vous souhaitez le faire à l'aide d'outils standard, le pipeline suivant devrait fonctionner:
find . -type d | Perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2
C'est,
Pour limiter la profondeur trouvée, ajoutez l'argument -maxdepth à la commande find.
Si vous voulez que les répertoires soient listés dans le même ordre que ceux qui les trouvent, utilisez "sort -n -s" au lieu de "sort -n"; l'indicateur "-s" stabilise le tri (c'est-à-dire qu'il préserve l'ordre d'entrée parmi les éléments qui se comparent également).
Mon sentiment est que c'est une meilleure solution que celles mentionnées précédemment. Cela implique grep et autres et une boucle, mais je trouve que cela fonctionne très bien, en particulier pour les cas où vous voulez que les choses soient mises en mémoire tampon et non pas la recherche complète en mémoire tampon.
Il consomme plus de ressources en raison de:
C'est bien parce que:
#!/bin/bash depth = 0 tandis que find -mindepth $ depth -maxdepth $ depth | grep '.' do depth = $ ((depth + 1)) done
Vous pouvez également l'ajuster sur une seule ligne assez (?) Facilement:
depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done
Mais je préfère les petits scripts à la frappe ...
Vous pouvez utiliser la commande find, find/path/to/dir -type d Voici donc un exemple de liste de répertoires dans le répertoire courant:
find . -type d
Je ne pense pas que vous puissiez le faire en utilisant des utilitaires intégrés, car lorsque vous parcourez une hiérarchie de répertoires, vous voulez presque toujours une recherche en profondeur d'abord, de haut en bas ou de bas en haut. Voici un script Python qui vous donnera une recherche en premier lieu:
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))
Modifier:
os.path
- module au lieu de os.stat
- fonction et stat
- module.list.pop
et list.extend
au lieu de del
et +=
les opérateurs.J'ai essayé de trouver un moyen de le faire avec find
mais il ne semble pas avoir quelque chose comme un -breadth
option. À moins d'écrire un correctif pour celui-ci, essayez l'incantation Shell suivante (pour 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
J'ai en quelque sorte trébuché dessus accidentellement, donc je ne sais pas si cela fonctionne en général (je le testais uniquement sur la structure de répertoires spécifique dont vous parliez)
Si vous voulez limiter la profondeur, mettez une variable de compteur dans la boucle externe, comme ça (j'ajoute également des commentaires à celle-ci):
# 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
(remplacez le 2 dans -lt 2
avec la profondeur)
Fondamentalement, cela implémente l'algorithme de recherche standard en largeur en utilisant $LIST
et $NLIST
comme une file d'attente de noms de répertoires. Voici cette dernière approche en une ligne pour un copier-coller facile:
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
Sans l'ordre mérité: trouver -maxdepth -type d
Pour obtenir la commande méritée, vous devez faire la récursivité vous-même, avec ce petit 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"
Ensuite, vous pouvez appeler ce script avec le répertoire de base des paramètres et la profondeur.
Voici une façon possible d'utiliser la recherche. Je ne l'ai pas testé à fond, alors méfiez-vous des utilisateurs ...
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
Quelque chose comme ça:
find . -type d |
Perl -lne'Push @_, $_;
print join $/,
sort {
length $a <=> length $b ||
$a cmp $b
} @_ if eof'