Znajdź listę katalogów jeden poziom głęboko od pasującego katalogu

13

Próbuję uzyskać listę katalogów, które są zawarte w określonym folderze.

Biorąc pod uwagę te przykładowe foldery:

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

Chciałbym polecenia, które zwróci:

XYZ
ABC
DEF
GHI

Zasadniczo szukam folderów wewnątrz wp-content / plugins /

Używanie findsprawiło, że jestem najbliżej, ale nie mogę używać -maxdepth, ponieważ folder jest zmiennie oddalony od miejsca, w którym szukam.

Uruchomienie następującego zwraca rekursywnie wszystkie katalogi potomne.

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
Nacięcie
źródło

Odpowiedzi:

14

Po prostu dodaj a, -pruneaby znalezione katalogi nie zostały umieszczone w:

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

Musisz to zacytować, *wp-content/plugins/*ponieważ jest to również glob powłoki.

Jeśli chcesz tylko nazwy katalogów, w przeciwieństwie do ich pełnej ścieżki, z GNU find, można wymienić -printw -printf '%f\n'lub przy założeniu ścieżki plików nie zawierają znaki nowej linii, rura wyjście powyższego polecenia awk -F / '{print $NF}'lub sed 's|.*/||'(zakładając również zawierać ścieżki pliku tylko prawidłowe znaki).

Z zsh:

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

**/jest dowolny poziom podkatalogów (funkcja pochodzących w zshna początku nighties, a teraz znaleźć w większości innych muszli jak ksh93, tcsh, fish, bash, yashchociaż na ogół pod pewnym opcja), (/)aby wybrać tylko pliki typu katalogu , Daby zawierać ukryte (kropka) te, :tdo dostać ogon (nazwa pliku).

Stéphane Chazelas
źródło
To znalezisko zamieni nowe wiersze w katalogach na ?. W przypadku bash (jak zaznaczono w pytaniu) to działa .
Izaak
@sorontar, findimplementacje, które generują ?znak zastępczy lub dowolny znak zastępczy, lub dowolną formę zmiany znaczenia znaków niedrukowalnych, robią to tylko wtedy, gdy dane wyjściowe trafiają do terminala, a nie do potoku takiego jak tutaj.
Stéphane Chazelas
Pierwsze (i jedyne nie zsh) polecenie, które jest w twojej odpowiedzi, nie ma potoków, to jest to, które przetestowałem i to, które zmienia znaki nowej linii. Po sondowaniu, jak powiedziałeś: „zakładając, że ścieżki do plików nie zawierają znaków nowej linii”, więc już przyznałeś, że nie działa również z nowymi liniami.
Izaak
@sorontar, przepraszam, myślałem, że komentujesz drugą część, aby powiedzieć, że będzie działać OK, ponieważ znaki nowej linii zostaną oznaczone znakiem ucieczki, więc nie złamie założenia, dla którego się przyjmujemy sed/ awkże wszystkie pliki są w linii. Teraz można argumentować, że uzyskanie ABC?BCDlub ABC\nBCDdla wyjścia interaktywnego / terminalowego byłoby bardziej przydatne niż uzyskanie dwóch ABCi BCDlinii dla wywoływanego katalogu $'ABC\nBCD. To na poziomie prezentacji użytkownika, moglibyśmy również $'AB\bC'zauważyć , że w przypadku pliku o nazwie , gdy dane wyjściowe trafiają do terminala, zobaczysz ACbez takiej ?zamiany ...
Stéphane Chazelas
Znajdź za pomocą -prune i użycie printf do modyfikacji formatu wyjściowego dało mi dokładnie to, o co prosiłem. Perfekcyjnie, dzięki!
Nick
4

Bash-ical:

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

drukuje:

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

lub

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

drukuje:

GHI
ABC
DEF
XYZ
Jeff Schaller
źródło
Nie, to również wydrukuje pliki wewnątrz katalogów. Proszę przeczytać moją odpowiedź.
Izaak
Słuszna uwaga; Dziękuję Ci! Ponownie odtworzyłem ich strukturę katalogów, ale nie umieściłem w nich plików testowych.
Jeff Schaller
4

Możesz mieć findponowną rekompensatę:

find / -type d -path *wp-content/plugins -exec find {} -maxdepth 1 -mindepth 1 -type d \;
DopeGhoti
źródło
3

Dla Bash: Simple (działa dla plików / katalogów ze spacjami i znakami nowej linii ):

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.

Wydrukuję:

GHI
ABC
DEF
XYZ

Nawet jeśli są tworzone pliki.

Izaak
źródło
Zauważ, że nie zagląda do ukrytych katalogów, pomija ukryte pliki (zobacz dotglobopcję, jeśli jest to niepożądane) i zawiera oprócz linków dowiązania symboliczne do katalogów ( **przechodziłoby również dowiązania symboliczne w bash 4.2 i wcześniejszych).
Stéphane Chazelas
@ StéphaneChazelas ukryte pliki? Pytanie nie wymaga odpowiedzi, tylko reż. Tak, ukryte katalogi mogą być niezależnie wybrane (w razie potrzeby jako funkcja). I tak, dowiązania symboliczne nie są poprzeczne w obecnej wersji bash.
Izaak
1
proszę, nie traktuj moich komentarzy jako agresji. Głosowałem za odpowiedzią i dodałem notatkę poniżej, aby wskazać na niektóre fakty, które niekoniecznie są oczywiste. findnie wyklucza żadnego pliku. globs wyklucza pliki kropkowe, warto wskazać na różnicę między nimi.
Stéphane Chazelas
3

treeKomenda jest przeznaczony właśnie do tego celu. Głębokość można kontrolować za pomocą -Lflagi. Oto przykład na lokalnej stronie Wordpress, którą prowadzę:

$ 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
źródło
1

Opierając się na odpowiedzi DopeGhoti, co powiesz na pętlę dopasowania:

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

Powodem takiego działania jest to, że może to być mylące / uciążliwe dla wielu -execplików, przy jednoczesnym unikaniu problemów z osobliwymi nazwami plików zawierającymi \ n 'itd. -Print0 użyje separatorów zerowych między wynikami.

Ed Neville
źródło
0

Opierając się na tym, co zacząłeś:

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

egrep pobiera * wp-content / plugins / * i dowolne znaki do następnego ukośnika / lub końca wiersza $ - który zawiera żądaną część.

sed , z separatorem ~, wybiera żądaną część za pomocą pierwszego zestawu nawiasów () i używa \ 1 (tego, co chcesz) jako zamiennika wszystkiego

uniq odfiltrowuje duplikaty wyników

MikeD
źródło