Список подкаталогов только на глубину 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|^$"

Используя find

Использование 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

Детали поиска и базовое имя

Эта команда работает путем создания списка полных путей к файлам, которые имеют ровно 2 уровня по отношению к этому каталогу:

/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переключатель.


LOL, почти такой же ответ, великие умы и все такое :).
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-х уровней down ( 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должно решить эту проблему, верно? Также будет ждать ответа -exec basename {}
SLM

@ user66001 да, -type dнайдет каталоги. Это basenameочень хорошая идея, она напечатает только имя и удалит путь. Предполагая, что вы хотите только имена, это то, что вы должны делать. Посмотрите man basenameтакже man dirname.
Terdon

Спасибо, Тердон. Извините, что не пометили ваш ответ. Чувствуется , что текущая версия ОДС «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.