Trouver la liste des répertoires à un niveau de profondeur du répertoire correspondant

13

J'essaie d'obtenir une liste des répertoires contenus dans un dossier spécifique.

Étant donné ces exemples de dossiers:

foo/bar/test
foo/bar/test/css
foo/bar/wp-content/plugins/XYZ
foo/bar/wp-content/plugins/XYZ/js
foo/bar/wp-content/plugins/XYZ/css
baz/wp-content/plugins/ABC
baz/wp-content/plugins/ABC/inc
baz/wp-content/plugins/ABC/inc/lib
baz/wp-content/plugins/DEF
bat/bar/foo/blog/wp-content/plugins/GHI

Je voudrais une commande qui retournera:

XYZ
ABC
DEF
GHI

Essentiellement, je recherche les dossiers qui se trouvent à l'intérieur de wp-content / plugins /

L'utilisation findm'a rapproché le plus, mais je ne peux pas l'utiliser -maxdepth, car le dossier est éloigné de l'endroit où je cherche.

L'exécution de ce qui suit retourne récursivement tous les répertoires enfants.

find -type d -path *wp-content/plugins/*

foo/bar/wp-content/plugins/XYZ
foo/bar/wp-content/plugins/XYZ/js
foo/bar/wp-content/plugins/XYZ/css
baz/wp-content/plugins/ABC
baz/wp-content/plugins/ABC/inc
baz/wp-content/plugins/ABC/inc/lib
baz/wp-content/plugins/DEF
bat/bar/foo/blog/wp-content/plugins/GHI
pseudo
la source

Réponses:

14

Ajoutez simplement un -pruneafin que les répertoires trouvés ne soient pas descendus dans:

find . -type d -path '*/wp-content/plugins/*' -prune -print

Vous devez le citer *wp-content/plugins/*car c'est aussi un glob de shell.

Si vous ne voulez que les noms de répertoire par opposition à leur chemin complet, avec GNU find, vous pouvez remplacer le -printavec -printf '%f\n'ou en supposant que les chemins de fichier ne contiennent pas de caractères de nouvelle ligne, dirigez la sortie de la commande ci-dessus vers awk -F / '{print $NF}'ou sed 's|.*/||'(en supposant également que les chemins de fichier contiennent uniquement des caractères valides).

Avec zsh:

printf '%s\n' **/wp-content/plugins/*(D/:t)

**/est un niveau de sous - répertoires (fonction originaires zshau début des nuisettes, et maintenant dans la plupart des autres interpréteurs tels que ksh93, tcsh, fish, bash, yashbien que généralement sous une option), (/)pour sélectionner uniquement les fichiers de type répertoire , Dles inclure cachés (point), :tà récupérez la queue (nom du fichier).

Stéphane Chazelas
la source
Cette recherche convertira les sauts de ligne en dirs en a ?. Pour bash, (comme indiqué dans la question), cela fonctionne .
Isaac
@sorontar, les findimplémentations qui produisent un ?ou tout caractère de remplacement ou toute forme d'échappement pour les caractères non imprimables ne le font que lorsque la sortie va à un terminal, pas quand elle va à un canal comme ici.
Stéphane Chazelas
La première commande (et uniquement non zsh) qui se trouve dans votre réponse n'a pas de canaux, c'est celle que j'ai testée et c'est celle qui change les sauts de ligne. Lorsqu'il est canalisé, comme vous l'avez dit: "en supposant que les chemins de fichier ne contiennent pas de caractères de nouvelle ligne", vous avez donc déjà admis qu'il échoue également avec les nouvelles lignes.
Isaac
@sorontar, désolé, je pensais que vous commentiez la deuxième partie pour dire que cela fonctionnerait bien car les sauts de ligne seraient échappés, donc ne briserait pas l'hypothèse que nous faisons pour sed/ awkque tous les fichiers sont sur une ligne. Maintenant, on peut faire valoir que l' obtention d' un ABC?BCDou ABC\nBCDpour une sortie interactive / terminal serait plus utile que d' obtenir deux ABCet BCDlignes pour un répertoire appelé $'ABC\nBCD. C'est au niveau de la présentation utilisateur, on pourrait aussi signaler que pour un fichier appelé $'AB\bC', lorsque la sortie va sur un terminal, on verrait ACsans un tel ?remplacement ...
Stéphane Chazelas
La recherche avec -prune et l'utilisation de printf pour modifier le format de sortie m'ont donné exactement ce que je demandais. Parfait merci!
Nick
4

Bash-iquement:

shopt -s globstar
printf "%s\n" **/wp-content/plugins/*

impressions:

bat/bar/foo/blog/wp-content/plugins/GHI
baz/wp-content/plugins/ABC
baz/wp-content/plugins/DEF
foo/bar/wp-content/plugins/XYZ

ou

shopt -s globstar
for d in **/wp-content/plugins/*; do printf "%s\n" ${d##*/}; done

impressions:

GHI
ABC
DEF
XYZ
Jeff Schaller
la source
Non, cela imprimera également les fichiers dans les répertoires. Veuillez lire ma réponse.
Isaac
Bon point; Merci! J'avais recréé leur structure de répertoires, mais je n'y avais pas placé de fichiers de test.
Jeff Schaller
4

Vous pourriez avoir findrecurse, en quelque sorte:

find / -type d -path *wp-content/plugins -exec find {} -maxdepth 1 -mindepth 1 -type d \;
DopeGhoti
la source
3

Pour Bash: Simple (fonctionne pour les fichiers / répertoires avec des espaces et des retours à la ligne ):

shopt -s globstar                    # allow ** for several dirs.
a=(**/wp-content/plugins/*/)         # capture only wanted dirs.
a=("${a[@]%/}")                      # remove trailing slash (dirs) `/`.
printf '%s\n' "${a[@]##*/}"          # print only the last dir name.

Imprimera:

GHI
ABC
DEF
XYZ

Même s'il y a des fichiers créés.

Isaac
la source
Notez qu'il ne regarde pas à l'intérieur des répertoires cachés, ignore les fichiers cachés (voir l' dotgloboption si cela n'est pas souhaité) et inclut des liens symboliques vers des répertoires en plus des répertoires ( **traverserait également les liens symboliques dans bash 4.2 et versions antérieures).
Stéphane Chazelas
@ StéphaneChazelas fichiers cachés? La question n'en demande pas, seulement des dir. Oui, les répertoires cachés peuvent être sélectionnés indépendamment (en tant que fonctionnalité, si vous le souhaitez). Et oui, les liens symboliques ne sont pas transversaux dans la version actuelle de bash.
Isaac
1
veuillez ne pas considérer mes commentaires comme des agressions. J'ai voté contre votre réponse et ajouté une note en dessous pour souligner certains faits qui ne sont pas nécessairement évidents. findn'exclut aucun fichier. globs exclut les fichiers de points, il convient de souligner la différence entre les deux.
Stéphane Chazelas
3

La treecommande est conçue exactement à cet effet. La profondeur peut être contrôlée avec le -Ldrapeau. Voici un exemple sur un site Wordpress local que je maintiens:

$ tree -L 1 wp-content/
wp-content/
├── index.php
├── plugins
└── themes

2 directories, 1 file

$ tree -L 2 wp-content/
wp-content/
├── index.php
├── plugins
   ├── akismet
   ├── contact-form-7
   ├── index.php
   └── wordpress-seo
└── themes
    ├── index.php
    ├── twentyfifteen
    └── twentysixteen

11 directories, 3 files

$ tree -L 1 wp-content/plugins/
wp-content/plugins/
├── akismet
├── contact-form-7
├── index.php
└── wordpress-seo

5 directories, 1 file
dotancohen
la source
1

S'appuyant sur la réponse de DopeGhoti, que diriez-vous de la boucle de correspondance:

find / -type d -iregex '.*/wp-content/plugins' -print0 | while read -r -d $'\0' D; do
    find "$D" -maxdepth 2 -mindepth 1
done

La raison pour cela est que vous pouvez trouver cela déroutant / lourd avec plusieurs -exec, tout en évitant les problèmes avec les noms de fichiers particuliers contenant \ n '', etc. -print0 utilisera des séparateurs nuls entre les résultats.

Ed Neville
la source
0

S'appuyant sur ce que vous avez commencé:

find -type d -path *wp-content/plugins/* | egrep -o "wp-content/plugins/[^/]+($|/)" | sed -r "s~wp-content/plugins/([^/]+)($|/)~\1~" | uniq  

egrep saisit * wp-content / plugins / * et tous les caractères jusqu'à la prochaine barre oblique / ou fin de ligne $ - qui inclut la partie que vous voulez.

sed , avec un délimiteur ~, sélectionne la portion que vous voulez en utilisant le premier jeu de parenthèses () et utilise \ 1 (ce que vous voulez) comme remplacement de tout

uniq filtre les résultats en double

MikeD
la source