Elenca le sottodirectory solo a livello n


58

Festival memorizza i dati del pacchetto vocale nella seguente struttura di directory di esempio:

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

Qual è il one-liner più semplice (preferibilmente usando ls) per stampare solo quelli <voicepack name>, in tutte le <language>sottodirectory potenzialmente numerose ?

Risposte:


80

Sono su Fedora e questi voice pack si trovano in una posizione leggermente diversa:

$ 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

Puoi semplicemente modificarlo in questo modo:

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

Utilizzando find

L'uso lsin questo maniero è generalmente disapprovato perché l'output di lsè difficile da analizzare. Meglio usare il findcomando, in questo modo:

$ 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

Dettagli di find & basename

Questo comando funziona producendo un elenco di percorsi completi per i file che hanno esattamente 2 livelli di profondità rispetto a questa directory:

/usr/share/festival/lib/voices

Questo elenco è simile al seguente:

$ 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

Ma vogliamo l'ultima parte di queste directory, il nodo foglia. Quindi possiamo usarlo basenameper analizzarlo:

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

Mettendo tutto insieme, possiamo fare in modo che il findcomando passi ogni directory profonda a 2 livelli al basenamecomando. La notazione basename {}è ciò che sta facendo queste conversioni di basename. Trova lo chiama tramite il suo -execinterruttore.


lol, più o meno esattamente la stessa risposta, grandi menti e tutto ciò che :).
— terdon

+1 - Per coloro che sono inciampati quando capiscono cosa -exec basename {}fa, potresti spiegarlo qui?
— user66001

@ user66001 - fammi sapere se questo lo spiega abbastanza.
— slm

@ user66001 - puoi accettare una delle risposte se risolve il tuo problema con soddisfazione 8-)
— slm

1
Il comando find è quello di cui ho bisogno il 99% delle volte. Limite sia massimo che minimo era la chiave - ho fatto solo max. Esempio: find ~/ -maxdepth 1 -mindepth 1 -type d | xargs du -csh | sort -h trova le directory più grandi ordinate per dimensione
— oligofren

23

Il più semplice è

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

Questo viene espanso dalla shell in tutte le sottodirectory /usr/share/festival/voices/e quindi nei contenuti di ciascuna di tali sottodirectory.

Se vuoi solo scendere a un livello specifico come suggerisce il tuo titolo, con alcune implementazioni findcome GNU e alcuni BSD:

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

Questo troverà tutte le directory ( -type d) che si trovano in una sottodirectory di a /usr/share/festival/voices/causa di mindepth 2ma non sono più profonde di 3 livelli in basso ( maxdepth 3). Da 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.

Sì, è come guardarsi allo specchio Cool
— slm

+1 È interessante il modo in cui entrambi avete ottenuto 2 voti. Il voto incrociato spiega 1 ciascuno;) PS Volevo i nomi delle directory, quindi basta cambiarlo -type fper -type drisolverlo, giusto? Aspetterà anche la risposta di slm in merito allo scopo di-exec basename {}
— user66001

@ user66001 sì, -type dtroverà le directory. È basenameun'ottima idea, stamperà solo il nome e rimuoverà il percorso. Supponendo che tu voglia solo nomi, ecco cosa dovresti fare. Dai un'occhiata man basenamee anche man dirname.
— terdon

Grazie, scusami per non aver contrassegnato la tua come risposta. Ritenuto che l'attuale versione di SLM s' ha più informazioni, per coloro che ne hanno bisogno.
— user66001

1
@ user66001 prima di tutto, hai assolutamente ragione, slm's è davvero migliore. Secondo, non dovresti mai scusarti per non aver accettato, ce ne può essere solo uno e quello dovrebbe essere quello che ritieni migliore :).
— terdon

6

La risposta accettata funziona correttamente ma è in qualche modo inefficiente perché genera un nuovo basenameprocesso per ogni sottodirectory:

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

Quando possibile, è preferibile utilizzare le funzionalità integrate findper evitare le spese dei processi di generazione. findha una capacità abbastanza estesa di modificare il suo output stampato usando l' -printfazione. L' -print azione predefinita stampa l'intero percorso, ma utilizzando -printfe una stringa di formato è possibile selezionare parti del percorso per la stampa. Per estrarre solo la parte del nome file del percorso senza le directory principali (come basename fa), la stringa di formato è %f. Per inserire una nuova riga dopo ogni nome file, includere \ncome segue:

$ 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 Grazie per la risposta Michael. Riesco a vedere il vantaggio del modo di farlo anche nella tua risposta, ma dato il lavoro messo nella risposta di slm ho due idee per cambiare la risposta accettata. Se @slm vede questo e non ha problemi a scegliere questo sopra il suo, tornerò qui per cambiare la risposta accettata.
— user66001

1
La risposta di @ slm è ben spiegata e copre il modello più generale di utilizzo findcon comandi esterni arbitrari; è solo meno efficiente per le operazioni integrate find. Avevo preso in considerazione l'aggiunta di un commento alla sua risposta, ma ciò richiede più reputazione di me. Non è necessario modificare la risposta accettata, poiché la risposta attualmente accettata è corretta, ben spiegata e utilizzabile come modello per il caso più generale; Volevo solo sottolineare che per questo caso specifico esiste un metodo più efficiente.
— Michael Henry,

0

TLDR; per quelli che vengono qui basandosi sul titolo di questa domanda; a "Elenca le sottodirectory solo a livello n profondo": utilizzare

find -maxdepth N

dov'è Nun numero qualsiasi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.