Encontre a lista de diretórios em um nível a partir do diretório correspondente

13

Estou tentando obter uma lista de diretórios contidos em uma pasta específica.

Dados esses exemplos de pastas:

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

Eu gostaria de um comando que retorne:

XYZ
ABC
DEF
GHI

Basicamente, estou procurando as pastas que estão dentro do wp-content / plugins /

O uso findme aproximou mais, mas não posso usá-lo -maxdepth, porque a pasta está longe de onde estou pesquisando.

A execução do seguinte retorna todos os diretórios filhos, recursivamente.

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
usuario
fonte

Respostas:

14

Basta adicionar um -prunepara que os diretórios encontrados não sejam desceu para:

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

Você precisa citar isso *wp-content/plugins/*, pois também é uma bola de fogo.

Se você deseja apenas os nomes dos diretórios, e não o caminho completo, com o GNU find, substitua o -printcom -printf '%f\n'ou assumindo que os caminhos do arquivo não contêm caracteres de nova linha, canalize a saída do comando acima para awk -F / '{print $NF}'ou sed 's|.*/||'(também assumindo que os caminhos do arquivo contenham somente caracteres válidos).

Com zsh:

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

**/é qualquer nível de subdiretórios (recurso originários zshno início nighties, e agora encontrados na maioria dos outros escudos como ksh93, tcsh, fish, bash, yashembora geralmente sob algum opção), (/)para selecionar apenas arquivos do tipo diretório , Dpara incluir as ocultas (ponto), :tpara pegue a cauda (nome do arquivo).

Stéphane Chazelas
fonte
Essa descoberta converterá novas linhas em dirs para a ?. Para o bash, (conforme marcado na pergunta), isso funciona .
sorontar
@sorontar, findimplementações que produzem um ?ou qualquer caractere de substituição ou qualquer forma de escape para caracteres não imprimíveis só fazem isso quando a saída vai para um terminal, não para um tubo como aqui.
Stéphane Chazelas
O primeiro comando (e apenas o não zsh) que está na sua resposta não possui canais, é o que eu testei e é o que altera as novas linhas. Quando canalizado, como você disse: "assumindo que os caminhos do arquivo não contêm caracteres de nova linha", você já admitiu que ele também falha com as novas linhas.
sorontar
@sorontar, desculpe, pensei que você estivesse comentando a segunda parte para dizer que funcionaria bem, pois as novas linhas seriam escapadas para não quebrar a suposição que estamos fazendo sed/ awkque todos os arquivos estão em uma linha. Agora, alguém pode argumentar que obter uma saída / ABC?BCDou ABC\nBCDinterativa / terminal seria mais útil do que obter duas linhas ABCe BCDum dir chamado $'ABC\nBCD. Que está no nível de apresentação do usuário, também poderíamos apontar que por um arquivo chamado $'AB\bC', quando a saída vai para um terminal, você veria ACsem tal ?substituição ...
Stéphane Chazelas
Encontre com -prune e usar printf para modificar o formato de saída me deu exatamente o que estava pedindo. Perfeito - obrigado!
Nick
4

Basicamente:

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

impressões:

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

impressões:

GHI
ABC
DEF
XYZ
Jeff Schaller
fonte
Não, isso também imprimirá arquivos dentro dos diretórios. Por favor, leia minha resposta.
sorontar 28/02
Bom ponto; obrigado! Eu recriei a estrutura de diretórios, mas não coloquei os arquivos de teste neles.
Jeff Schaller
4

Você poderia findrecursar, mais ou menos:

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

Para Bash: Simples (funciona para arquivos / diretórios com espaços e novas linhas ):

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

Mesmo se houver arquivos criados.

sorontar
fonte
Observe que ele não procura dentro de diretórios ocultos, ignora arquivos ocultos (consulte a dotglobopção se isso não for desejado) e inclui links simbólicos para diretórios além de diretórios ( **também atravessaria links simbólicos no bash 4.2 e versões anteriores).
Stéphane Chazelas
@ StéphaneChazelas arquivos ocultos? A pergunta não pede nada, apenas dirs. Sim, os diretórios ocultos podem ser selecionados independentemente (como um recurso, se desejado). E sim, links simbólicos não são transversais na versão atual do bash.
sorontar
1
por favor, não considere meus comentários como agressões. Votei na sua resposta e adicionei uma nota abaixo para apontar alguns fatos sobre ela que não são necessariamente óbvios. findnão exclui nenhum arquivo. globs exclui arquivos de ponto, vale a pena apontar como uma diferença entre os dois.
Stéphane Chazelas
3

O treecomando foi projetado exatamente para esse fim. A profundidade pode ser controlada com a -Lbandeira. Aqui está um exemplo em um site Wordpress local que eu mantenho:

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

Com base na resposta de DopeGhoti, que tal loop de correspondência:

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

A razão para fazê-lo dessa maneira é que você pode achar confuso / complicado com múltiplos -exec's, enquanto ainda evita problemas com nomes de arquivos peculiares que contêm \ n' ', etc. -print0 usará separadores nulos entre os resultados.

Ed Neville
fonte
0

Com base no que você começou:

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

egrep pega * wp-content / plugins / * e qualquer caractere até a próxima barra / ou final da linha $ - que inclui a parte que você deseja.

sed , com um delimitador ~, seleciona a parte que você deseja usando o primeiro conjunto de parênteses () e usa \ 1 (o que você deseja) como substituto de tudo

O uniq filtra resultados duplicados

MikeD
fonte