Список подкаталогов только на n-й уровень в глубину

Список подкаталогов только на n-й уровень в глубину

Festival хранит данные голосового пакета в следующем примере структуры каталогов:

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

Какой самый простой однострочный код (предпочтительно с использованием ls) позволит вывести только <voicepack name>символы ' во всех потенциально многочисленных <language>подкаталогах?

решение1

У меня 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в этом manor обычно не приветствуется, поскольку вывод 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 {}— это то, что делает эти преобразования базовых имен. Find вызывает его через свой -execпереключатель.

решение2

Самый простой - это

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

Оболочка расширяет его на все подкаталоги, /usr/share/festival/voices/а затем на содержимое каждого из этих подкаталогов.

Если вы хотите опуститься только до определенного уровня, как следует из вашего заголовка, с некоторыми реализациями вроде findGNU и некоторыми 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.

решение3

Theпринятый ответработает правильно, но несколько неэффективно, поскольку порождает новый 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

решение4

Для тех, кто использует bash и ищет что-то простое, используя ls:

ls -d $PWD/*

При создании псевдонима (в ~/.bash_aliases или где-либо еще) обязательно используйте одинарные кавычки:

alias ldf='ls -d $PWD/*'

Если не заключить его в кавычки, оболочка попытается выполнить ls.

Двойные кавычки создадут псевдоним со значением $PWD на момент создания псевдонима.

Вы можете использовать $(pwd), если предпочитаете, но я не вижу смысла в создании дочерней оболочки, когда bash предоставляет вам $PWD.

Связанный контент