Lista podkatalogów tylko na głębokości n

58

Festival przechowuje dane pakietu głosowego w następującej przykładowej strukturze katalogów:

/usr/share/festival/voices/<language>/<voicepack name>

Jaka jest najprostsza jedna linijka (najlepiej przy użyciu ls) do wydrukowania tylko tych <voicepack name>we wszystkich potencjalnie licznych <language>podkatalogach?

user66001
źródło

Odpowiedzi:

80

Jestem na Fedorze, a te pakiety głosowe znajdują się w nieco innej lokalizacji:

$ ls /usr/share/festival/lib/voices/*/ -1 | grep -vE "/usr|^$"
kal_diphone
ked_diphone
nitech_us_awb_arctic_hts
nitech_us_bdl_arctic_hts
nitech_us_clb_arctic_hts
nitech_us_jmk_arctic_hts
nitech_us_rms_arctic_hts
nitech_us_slt_arctic_hts

Możesz to zmodyfikować w następujący sposób:

$ ls /usr/share/festival/voices/*/ -1 | grep -vE "/usr|^$"

Używanie znajdź

Używanie lsw tym dworze jest zwykle niezadowolone, ponieważ wynik lsjest trudny do przeanalizowania. Lepiej użyć findpolecenia, tak:

$ find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 \
    -type d -exec basename {} \;
nitech_us_awb_arctic_hts
nitech_us_bdl_arctic_hts
nitech_us_slt_arctic_hts
nitech_us_jmk_arctic_hts
nitech_us_clb_arctic_hts
nitech_us_rms_arctic_hts
ked_diphone
kal_diphone

Szczegóły find & basename

To polecenie działa, tworząc listę pełnych ścieżek do plików o głębokości dokładnie 2 poziomów w odniesieniu do tego katalogu:

/usr/share/festival/lib/voices

Ta lista wygląda następująco:

$ find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 
/usr/share/festival/lib/voices/us/nitech_us_awb_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_bdl_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_slt_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_jmk_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_clb_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_rms_arctic_hts
/usr/share/festival/lib/voices/english/ked_diphone
/usr/share/festival/lib/voices/english/kal_diphon

Ale chcemy ostatnią część tych katalogów, węzeł liścia. Możemy więc wykorzystać to basenamedo przeanalizowania:

$ basename /usr/share/festival/lib/voices/us/nitech_us_awb_arctic_hts
nitech_us_awb_arctic_hts

Podsumowując, możemy sprawić, że findpolecenie przekaże każdemu głębokiemu katalogowi 2 poziomy do basenamepolecenia. Notacja basename {}jest tym, co robi te konwersje basename. Znajdź połączenia za pomocą -execprzełącznika.

slm
źródło
lol, właściwie dokładnie ta sama odpowiedź, świetne umysły i tak dalej :).
terdon
+1 - -exec basename {}Czy możesz wyjaśnić tym, którzy wpadają w potrzaski, gdy zastanawiają się, co to robi?
user66001
@ user66001 - daj mi znać, jeśli to wystarczy.
slm
@ user66001 - możesz zaakceptować jedną z odpowiedzi, jeśli rozwiąże ona twój problem w sposób satysfakcjonujący 8-)
slm
1
Potrzebuję polecenia Znajdź w 99% przypadków. Kluczem było ograniczenie zarówno maksymalnego, jak i minimalnego - zrobiłem tylko maks. Przykład: find ~/ -maxdepth 1 -mindepth 1 -type d | xargs du -csh | sort -h Znajduje największe katalogi posortowane według wielkości
oligofren,
23

Najłatwiej jest

ls -d /usr/share/festival/voices/*/*

To jest rozszerzane przez powłokę do wszystkich podkatalogów, /usr/share/festival/voices/a następnie do zawartości każdego z tych podkatalogów.

Jeśli chcesz schodzić tylko do określonego poziomu, jak sugeruje Twój tytuł, z pewnymi implementacjami, findtakimi jak GNU i niektóre BSD:

find /usr/share/festival/voices/ -mindepth 2 -maxdepth 3 -type d

To znajdzie wszystkie katalogi ( -type d), które znajdują się w podkatalogu z /usr/share/festival/voices/powodu, mindepth 2ale nie głębszego niż 3 poziomy w dół ( maxdepth 3). Od man find:

   -maxdepth levels
          Descend at most levels (a non-negative integer) levels of direc
          tories below the command line arguments.  -maxdepth 0
           means only apply the tests and  actions  to  the  command  line
          arguments.

   -mindepth levels
          Do  not apply any tests or actions at levels less than levels (a
          non-negative integer).  -mindepth  1  means  process  all  files
          except the command line arguments.
terdon
źródło
Tak, to jak patrzenie w lustro 8-)
slm
+1 To, jak oboje otrzymaliście 2 głosy, jest interesujące. Głosowanie krzyżowe wyjaśnia po 1;) PS Chciałem nazw katalogów, więc wystarczy zmienić, -type faby -type drozwiązać ten problem, prawda? -exec basename {}
Oczekuje
@ user66001 tak, -type dznajdzie katalogi. basenameTo bardzo dobry pomysł, będzie drukować tylko nazwę i usunąć ścieżkę. Zakładając, że chcesz tylko imion, powinieneś to zrobić. Zobacz man basenametakże man dirname.
terdon
Dzięki terdon - przepraszam, że nie oznaczyłem cię jako odpowiedzi. Czułem, że obecna wersja SLM 's zawiera więcej informacji dla tych, którzy jej potrzebują.
user66001
1
@ user66001 po pierwsze, masz absolutną rację, slm's jest rzeczywiście lepszy. Po drugie, nigdy nie należy przepraszać za brak akceptacji, może być tylko jeden i taki powinien być najlepszy :).
terdon
6

Akceptowane odpowiedź działa poprawnie, ale jest nieco nieefektywne, ponieważ ikra nowy basenameproces dla każdego podkatalogu:

find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 \
    -type d -exec basename {} \;

Jeśli to możliwe, lepiej jest korzystać z wbudowanych funkcji, findaby uniknąć kosztów procesów odradzania. findma dość szerokie możliwości modyfikowania wydruków za pomocą -printfakcji. Domyślna -print akcja drukuje całą ścieżkę, ale przy użyciu -printfi ciągu formatującego można wybrać fragmenty ścieżki do wydrukowania. Aby wyodrębnić tylko część nazwy pliku ścieżki bez wiodących katalogów (jak to basename robi), ciąg formatu to %f. Aby wstawić znak nowej linii po każdej nazwie pliku, wykonaj \nnastępujące czynności:

$ find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 \
    -type d -printf '%f\n'
nitech_us_awb_arctic_hts
nitech_us_bdl_arctic_hts
nitech_us_slt_arctic_hts
nitech_us_jmk_arctic_hts
nitech_us_clb_arctic_hts
nitech_us_rms_arctic_hts
ked_diphone
kal_diphone
Michael Henry
źródło
+1 Dzięki za odpowiedź Michael. Widzę również przewagę tego sposobu w twojej odpowiedzi, ale biorąc pod uwagę pracę włożoną w odpowiedź SLM, nie mogę się zdecydować na zmianę zaakceptowanej odpowiedzi. Jeśli @slm to zobaczy i nie będzie miał problemów z wybraniem tego nad swoim, wrócę tutaj, aby zmienić zaakceptowaną odpowiedź.
user66001
1
Odpowiedź @ slm jest dobrze wyjaśniona i obejmuje bardziej ogólny wzorzec korzystania findz dowolnych poleceń zewnętrznych; jest po prostu mniej wydajny w przypadku wbudowanych operacji find. Zastanawiałem się nad dodaniem komentarza do jego odpowiedzi, ale to wymaga więcej reputacji niż ja. Nie ma potrzeby zmiany przyjętej odpowiedzi, ponieważ obecnie akceptowana odpowiedź jest poprawna, dobrze wyjaśniona i użyteczna jako wzorzec dla bardziej ogólnego przypadku; Chciałem tylko zaznaczyć, że w tym konkretnym przypadku istnieje bardziej skuteczna metoda.
Michael Henry
0

TLDR; dla tych, którzy dopiero przybywają tutaj na podstawie tytułu tego pytania; na „Lista podkatalogów tylko na głębokość n”: użyj

find -maxdepth N

gdzie Njest dowolna liczba.

Gabriel Staples
źródło