Listar subdiretórios com apenas n níveis de profundidade

Listar subdiretórios com apenas n níveis de profundidade

O Festival armazena dados do pacote de voz na seguinte estrutura de diretórios de exemplo:

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

Qual é a linha mais simples (de preferência usando ls) para imprimir apenas os 's, em todos os subdiretórios <voicepack name>potencialmente numerosos ?<language>

Responder1

Estou no Fedora e esses pacotes de voz estão em um local um pouco diferente:

$ 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

Você pode simplesmente modificar isso assim:

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

Usando encontrar

O uso lsnesta mansão normalmente é desaprovado porque a saída de lsé difícil de analisar. Melhor usar o findcomando, assim:

$ 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

Detalhes de localização e nome de base

Este comando funciona produzindo uma lista de caminhos completos para arquivos com exatamente 2 níveis de profundidade em relação a este diretório:

/usr/share/festival/lib/voices

Esta lista é assim:

$ 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

Mas queremos a última parte desses diretórios, o nó folha. Portanto, podemos usar basenamepara analisá-lo:

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

Juntando tudo, podemos fazer o findcomando passar cada diretório profundo de 2 níveis para o basenamecomando. A notação basename {}é o que está fazendo essas conversões de nome base. Encontre chamadas através do -execswitch.

Responder2

O mais fácil é

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

Isso é expandido pelo shell para todos os subdiretórios /usr/share/festival/voices/e depois para o conteúdo de cada um desses subdiretórios.

Se você deseja apenas descer para um nível específico como o título sugere, com algumas implementações findcomo GNU e alguns BSD:

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

Isso encontrará todos os diretórios ( -type d) que estão em um subdiretório por /usr/share/festival/voices/causa de, mindepth 2mas não estão mais profundos do que 3 níveis abaixo ( maxdepth 3). De 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.

Responder3

Oresposta aceitafunciona corretamente, mas é um tanto ineficiente porque gera um novo basenameprocesso para cada subdiretório:

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

Quando possível, é preferível usar recursos integrados findpara evitar despesas com processos de geração. findtem uma capacidade bastante extensa de modificar sua saída impressa usando a -printfação. A ação padrão -print imprime o caminho inteiro, mas usando -printfuma string de formato é possível selecionar partes do caminho para impressão. Para extrair apenas a parte do nome do arquivo do caminho sem os diretórios iniciais (como basename acontece), a string de formato é %f. Para colocar uma nova linha após cada nome de arquivo, inclua \no seguinte:

$ 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

Responder4

Para alguém que usa o bash e procura algo simples apenas usando ls:

ls -d $PWD/*

Ao criar um alias (em ~/.bash_aliases ou qualquer outro lugar), certifique-se de usar aspas simples:

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

Não citá-lo resultará no shell tentando executar ls.

Aspas duplas criarão o alias com o valor de $PWD no momento do alias.

Você poderia usar $(pwd) se preferir, mas não vejo sentido em gerar um sub-shell quando o bash fornece $PWD para você.

informação relacionada