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.