Encuentra la lista de directorios a un nivel de profundidad del directorio correspondiente

13

Estoy tratando de obtener una lista de directorios que están contenidos dentro de una carpeta específica.

Dados estos ejemplos de carpetas:

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

Me gustaría un comando que regrese:

XYZ
ABC
DEF
GHI

Básicamente, estoy buscando las carpetas que están dentro de wp-content / plugins /

El uso findme ha acercado más, pero no puedo usarlo -maxdepthporque la carpeta está muy lejos de donde estoy buscando.

La ejecución de lo siguiente devuelve todos los directorios secundarios, de forma recursiva.

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
Mella
fuente

Respuestas:

14

Simplemente agregue un -prunepara que los directorios encontrados no desciendan en:

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

Debe citar eso, *wp-content/plugins/*ya que también es un globo de shell.

Si solo desea los nombres de directorio en lugar de su ruta completa, con GNU find, puede reemplazarlos -printcon -printf '%f\n'o suponiendo que las rutas de archivo no contengan caracteres de nueva línea, canalice la salida del comando anterior a ( awk -F / '{print $NF}'o sed 's|.*/||'suponiendo que las rutas de archivo contengan solo caracteres válidos).

Con zsh:

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

**/es cualquier nivel de subdirectorios (función originaria de zshprincipios de los años camisones, y ahora se encuentra en la mayoría de las otras cáscaras como ksh93, tcsh, fish, bash, yashaunque por lo general bajo alguna opción), (/)para seleccionar sólo los archivos de tipo directorio , Dpara incluir los ocultos (punto), :ta obtener la cola (nombre del archivo).

Stéphane Chazelas
fuente
Este hallazgo convertirá nuevas líneas en directorios a a ?. Para bash, (como se etiqueta en la pregunta) esto funciona .
Isaac
@sorontar, las findimplementaciones que generan un ?carácter de reemplazo o cualquier tipo de escape o cualquier forma de escape para caracteres no imprimibles solo lo hacen cuando la salida va a una terminal, no cuando va a una tubería como aquí.
Stéphane Chazelas
El primer comando (y solo no zsh) que está en su respuesta no tiene canalizaciones, es el que probé y es el que cambia las nuevas líneas. Cuando se canaliza, como dijiste: "suponiendo que las rutas de archivo no contengan caracteres de nueva línea", entonces, ya admitiste que también falla con las nuevas líneas.
Isaac
@sorontar, lo siento, pensé que estabas comentando la segunda parte de decir que iba a funcionar bien, ya que los saltos de línea se escaparon por lo que no se rompería el supuesto de que estamos haciendo para sed/ awkque todos los archivos están en una línea. Ahora, uno puede argumentar que obtener una ABC?BCDo ABC\nBCDpara una salida interactiva / terminal sería más útil que obtener dos ABCy BCDlíneas para un directorio llamado $'ABC\nBCD. Eso está al nivel de la presentación del usuario, también podríamos señalar que para un archivo llamado $'AB\bC', cuando la salida va a una terminal, AC?
verías
Buscar con -prune y usar printf para modificar el formato de salida me dio exactamente lo que estaba pidiendo. ¡Perfecto gracias!
Nick
4

Básicamente:

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

huellas dactilares:

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

o

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

huellas dactilares:

GHI
ABC
DEF
XYZ
Jeff Schaller
fuente
No, eso también imprimirá archivos dentro de los directorios. Por favor lee mi respuesta.
Isaac
Buen punto; ¡gracias! Había recreado su estructura de directorios, pero no había colocado archivos de prueba en ellos.
Jeff Schaller
4

Podría tener findrecurrencia, más o menos:

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

Para Bash: Simple (funciona para archivos / directorios con espacios y líneas nuevas ):

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.

Imprimir:

GHI
ABC
DEF
XYZ

Incluso si hay archivos creados.

Isaac
fuente
Tenga en cuenta que no mira dentro dotglobde directorios ocultos, omite archivos ocultos (vea la opción si no es deseado) e incluye enlaces simbólicos a directorios además de directorios ( **también atravesaría enlaces simbólicos en bash 4.2 y versiones anteriores).
Stéphane Chazelas
@ StéphaneChazelas archivos ocultos? La pregunta no pide ninguno, solo dirs. Sí, los directorios ocultos podrían seleccionarse independientemente (como una característica, si lo desea). Y sí, los enlaces simbólicos no son transversales en la versión actual de bash.
Isaac
1
por favor no consideren mis comentarios como agresiones. Voté su respuesta y agregué una nota debajo para señalar algunos hechos al respecto que no son necesariamente obvios. findno excluye ningún archivo. Globs excluye los archivos de puntos, vale la pena señalar como una diferencia entre los dos.
Stéphane Chazelas
3

El treecomando está diseñado exactamente para este propósito. La profundidad se puede controlar con la -Lbandera. Aquí hay un ejemplo en un sitio local de Wordpress que mantengo:

$ 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
fuente
1

Sobre la base de la respuesta de DopeGhoti, ¿qué tal el ciclo de coincidencia:

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

La razón para hacerlo de esta manera es que puede resultar confuso / engorroso con múltiples -exec's, al tiempo que evita problemas con nombres de archivo peculiares que contienen \ n' ', etc. -print0 usará separadores nulos entre los resultados.

Ed Neville
fuente
0

Sobre la base de lo que empezaste:

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

egrep toma * wp-content / plugins / * y cualquier carácter hasta la siguiente barra diagonal o final de línea $, que incluye la parte que desea.

sed , con un delimitador ~, selecciona la parte que desea utilizando el primer conjunto de paréntesis () y utiliza \ 1 (lo que desea) como reemplazo de todo

uniq filtra resultados duplicados

MikeD
fuente