Перелічіть підкаталоги глибиною лише n рівнів


58

Дані фестивалю зберігають дані голосових пакетів у такій прикладі структури каталогу:

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

Який найпростіший однолінійний текст (бажано за допомогою ls) для друку лише цих матеріалів <voicepack name>у всіх потенційно численних <language>підкаталогах?

Відповіді:


80

Я в Fedora, і ці голосові пакети знаходяться в дещо іншому місці:

$ 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

Ви можете просто змінити це так:

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

Використання знахідки

Застосування lsв цій садибі, як правило, нахмуриться, оскільки висновок lsскладно проаналізувати. Краще використовувати findкоманду, наприклад так:

$ 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

Деталі пошуку та базової назви

Ця команда працює, створюючи список повних шляхів до файлів, що мають глибину точно на два рівні щодо цього каталогу:

/usr/share/festival/lib/voices

Цей список виглядає приблизно так:

$ 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

Але ми хочемо останню частину цих каталогів, листовий вузол. Тож ми можемо використати basenameдля розбору:

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

Збираючи все це разом, ми можемо змусити findкоманду передавати кожну глибинну директорію 2 рівня до basenameкоманди. Позначення basename {}- це, що робить ці перетворення базових імен. Знайдіть дзвінки за допомогою -execперемикача.


лол, в значній мірі точно таку ж відповідь, великі уми і все , що :).
terdon

+1 - Для тих, хто потрапляє в очі, розуміючи, що -exec basename {}робить, ви могли б пояснити тут?
user66001

@ user66001 - дайте мені знати, чи це пояснює це достатньо.
slm

@ user66001 - ви можете прийняти одну з відповідей, якщо вона вирішить вашу проблему на ваше задоволення 8-)
slm

1
Команда find - це те, що мені потрібно 99% часу. Обмеження як max, так і min було ключовим - я робив лише max. Приклад: find ~/ -maxdepth 1 -mindepth 1 -type d | xargs du -csh | sort -h Знаходить найбільші каталоги, відсортовані за розміром
oligofren

23

Найпростіше

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

Це розширюється оболонкою на всі підкаталоги /usr/share/festival/voices/та потім на вміст кожного з цих підкаталогів.

Якщо ви хочете лише опуститися на певний рівень, як підказує ваш заголовок, з деякими реалізаціями, findтакими як GNU та деякі BSD:

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

Це знайде всі каталоги ( -type d), які знаходяться в підкаталозі /usr/share/festival/voices/через, mindepth 2але не глибші на 3 рівні вниз ( maxdepth 3). Від 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.

Так, це виглядає як у дзеркалі 8-)
slm

+1 Як ви обидва отримали 2 голоси цікаво. Хрест голосування пояснити кожен 1;) PS Я хотів імена каталогів, так просто змінити , -type fщоб -type dповинні вирішити цю проблему, НЕ так? Буде також чекати відповіді slm щодо мети-exec basename {}
user66001

@ user66001 так, -type dзнайде каталоги. Це basenameдуже гарна ідея, вона надрукує лише ім'я та видалить шлях. Якщо припустити, що ви хочете лише імена, саме це вам слід зробити. Подивіться man basenameі також man dirname.
terdon

Дякую тердон - Вибачте, що не позначив вашу відповідь. Відчув, що поточна версія slm 's має більше інформації для тих, хто її потребує.
user66001

1
@ user66001 Перш за все, ви абсолютно праві, slm's дійсно краще. По-друге, ви ніколи не повинні просити вибачення за те, що не приймаєте, може бути лише одне, і це має бути той, який ви вважаєте найкращим :).
terdon

6

Прийнято відповідь працює правильно , але кілька неефективно , оскільки він породжує новий basenameпроцес для кожного підкаталогу:

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

Коли це можливо, бажано використовувати функції, вбудовані, findщоб уникнути витрат нерестових процесів. findмає досить широку можливість змінювати друкований вихід за допомогою -printfдії. Дія за замовчуванням -print друкує весь шлях, але за допомогою -printfта рядка формату можна вибрати частини шляху для друку. Щоб витягти лише частину імені файлу шляху без провідних каталогів (як basename це робиться), рядок формату є %f. Щоб розмістити новий рядок після кожного імені файлу, додайте \nнаступне:

$ 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

+1 Дякую за вашу відповідь, Майкл. Я також бачу перевагу перед способом зробити це у вашій відповіді, але, враховуючи роботу, вкладену у відповідь slm, я замислююся над переключенням прийнятої відповіді. Якщо @slm бачить це і не має проблем з його вибором, я повернусь сюди, щоб змінити прийняту відповідь.
user66001

1
@ відповідь slm добре пояснена і охоплює більш загальну схему використання findз довільними зовнішніми командами; він просто менш ефективний для вбудованих операцій find. Я розглядав можливість додати коментар до своєї відповіді, але це вимагає більшої репутації, ніж я. Не потрібно змінювати прийняту відповідь, оскільки прийнята на даний момент відповідь є правильною, добре поясненою та корисною як зразок для більш загального випадку; Я просто хотів зазначити, що для цього конкретного випадку існує більш ефективний метод.
Майкл Генрі

0

TLDR; для тих, хто щойно прийшов сюди, виходячи з назви цього питання; до "Список підкаталогів лише на глибині n рівня": використання

find -maxdepth N

де Nбудь-яке число.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.