Trova l'elenco delle directory a un livello di profondità dalla directory corrispondente


13

Sto cercando di ottenere un elenco di directory contenute in una cartella specifica.

Dati questi esempi di cartelle:

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

Vorrei un comando che restituirà:

XYZ
ABC
DEF
GHI

In sostanza, sto cercando le cartelle che si trovano all'interno di wp-content / plugins /

L'uso findmi ha reso il più vicino, ma non posso usarlo -maxdepth, perché la cartella è variamente lontana da dove sto cercando.

L'esecuzione di quanto segue restituisce tutte le directory secondarie, in modo ricorsivo.

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

Risposte:


14

Basta aggiungere un in -prunemodo che le directory trovate non siano discese in:

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

Devi citarlo *wp-content/plugins/*perché è anche un glob shell.

Se si desidera solo i nomi delle directory anziché il loro percorso completo, con GNU find, è possibile sostituire il -printcon -printf '%f\n'o supponendo che i percorsi dei file non contengano caratteri di nuova riga, reindirizzare l'output del comando precedente a awk -F / '{print $NF}'o sed 's|.*/||'(anche supponendo che i percorsi dei file contengano solo caratteri validi).

Con zsh:

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

**/è un qualsiasi livello di sottodirectory (funzione originari zshnei primi camicie da notte, e ora si trova nella maggior parte delle altre shell amano ksh93, tcsh, fish, bash, yashanche se generalmente in qualche opzione), (/)per selezionare solo i file di tipo directory , Dper includere nascosti (dot) quelli, :ta prendi la coda (nome del file).


Questa ricerca convertirà le nuove righe in dirs in a ?. Per bash (come indicato nella domanda) funziona .
Isaac

@sorontar, le findimplementazioni che generano un ?carattere sostitutivo o qualsiasi carattere sostitutivo o qualsiasi forma di escape per caratteri non stampabili lo fanno solo quando l'output arriva a un terminale, non quando viene indirizzato a una pipe come qui.
Stéphane Chazelas

Il primo (e unico non zsh) comando che è nella tua risposta non ha pipe, è quello che ho testato ed è quello che cambia newline. Quando esegui il piping, come hai detto: "supponendo che i percorsi dei file non contengano caratteri di nuova riga", quindi, hai già ammesso che fallisce anche con le nuove righe.
Isaac

@sorontar, mi dispiace, ho pensato che stavi commentando la seconda parte per dire che avrebbe funzionato bene dato che le nuove righe sarebbero sfuggite, quindi non avrebbe infranto il presupposto che stiamo facendo sed/ awkche tutti i file sono su una riga. Ora, si potrebbe sostenere che ottenere un output per ABC?BCDo ABC\nBCDinterattivo / terminale sarebbe più utile che ottenere due ABCe BCDrighe per una directory chiamata $'ABC\nBCD. È a livello di presentazione dell'utente, potremmo anche sottolineare che per un file chiamato $'AB\bC', quando l'output arriva a un terminale, vedresti ACsenza tale ?sostituzione ...
Stéphane Chazelas

Trova con -prune e l'uso di printf per modificare il formato di output mi ha dato esattamente quello che stavo chiedendo. Perfetto grazie!
Nick

4

Bash-camente:

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

stampe:

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

stampe:

GHI
ABC
DEF
XYZ

No, questo stamperà anche i file all'interno delle directory. Per favore leggi la mia risposta.
Isaac,

Buon punto; grazie! Avevo ricreato la loro struttura di directory, ma non ho inserito i file di test in essi.
Jeff Schaller

4

Potresti avere una findricorrenza, una specie di:

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

3

Per Bash: semplice (funziona per file / directory con spazi e newline ):

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.

Stampa:

GHI
ABC
DEF
XYZ

Anche se ci sono file creati.


Nota che non guarda dentro le directory nascoste, salta i file nascosti (vedi l' dotglobopzione se non lo desideri) e include collegamenti simbolici alle directory oltre alle directory ( **attraverserebbe anche i collegamenti simbolici in bash 4.2 e precedenti).
Stéphane Chazelas

@ StéphaneChazelas file nascosti? La domanda non richiede nessuno, solo dir. Sì, le directory nascoste possono essere selezionate in modo indipendente (come funzionalità, se lo si desidera). E sì, i collegamenti simbolici non sono trasversali nella versione corrente di bash.
Isaac

1
per favore, non considerare i miei commenti come aggressioni. Ho votato a favore della tua risposta e ho aggiunto una nota sotto per sottolineare alcuni fatti al riguardo che non sono necessariamente ovvi. findnon esclude alcun file. globs esclude i file dot, vale la pena sottolineare come una differenza tra i due.
Stéphane Chazelas

3

Il treecomando è progettato esattamente per questo scopo. La profondità può essere controllata con la -Lbandiera. Ecco un esempio su un sito Wordpress locale che 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

1

Sulla base della risposta di DopeGhoti, che ne dici di loop di abbinamento:

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

Il motivo per farlo in questo modo è che potresti trovarlo confuso / ingombrante con più -execdi uno, evitando comunque problemi con nomi di file particolari contenenti \ n '', ecc. -Print0 utilizzerà separatori nulli tra i risultati.


0

Sulla base di ciò che hai iniziato:

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

egrep prende * wp-content / plugins / * e tutti i caratteri fino alla barra successiva / o alla fine della riga $ - che include la porzione desiderata.

sed , con un delimitatore ~, seleziona la porzione desiderata usando il primo set di parentesi () e usa \ 1 (quello che vuoi) come sostituto di tutto

uniq filtra i risultati duplicati

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.