web-dev-qa-db-fra.com

Liste des sous-répertoires uniquement au niveau n profond

Festival stocke les données du pack vocal dans l'exemple de structure de répertoire suivant:

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

Quelle est la simple ligne (en utilisant de préférence ls) pour imprimer uniquement le <voicepack name>, dans tous les potentiellement nombreux <language> sous-répertoires?

67
user66001

Je suis sur Fedora, et ces packs vocaux sont dans un endroit légèrement différent:

$ 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

Vous pouvez simplement modifier ceci comme ceci:

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

Utilisation de find

L'utilisation de ls dans ce manoir est généralement désapprouvée car la sortie de ls est difficile à analyser. Mieux vaut utiliser la commande find, comme ceci:

$ 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

Détails sur find & basename

Cette commande fonctionne en produisant une liste de chemins complets vers des fichiers qui ont exactement 2 niveaux de profondeur par rapport à ce répertoire:

/usr/share/festival/lib/voices

Cette liste ressemble à ceci:

$ 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

Mais nous voulons la dernière partie de ces répertoires, le nœud feuille. Nous pouvons donc utiliser basename pour l'analyser:

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

En mettant tout cela ensemble, nous pouvons faire passer la commande find chaque répertoire profond de 2 niveaux à la commande basename. La notation basename {} est ce qui fait ces conversions de nom de base. Trouver l'appelle via c'est -exec commutateur.

87
slm

Le plus simple est

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

Celui-ci est étendu par le shell dans tous les sous-répertoires de /usr/share/festival/voices/ puis au contenu de chacun de ces sous-répertoires.

Si vous voulez seulement descendre à un niveau spécifique comme le suggère votre titre, avec quelques implémentations de find comme GNU et certains BSD:

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

Cela trouvera tous les répertoires (-type d) qui se trouvent dans un sous-répertoire de /usr/share/festival/voices/ à cause de mindepth 2 mais pas plus bas que 3 niveaux plus bas (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.
28
terdon

réponse acceptée fonctionne correctement mais est quelque peu inefficace car il engendre un nouveau processus basename pour chaque sous-répertoire:

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

Lorsque cela est possible, il est préférable d'utiliser des fonctionnalités intégrées à find pour éviter les frais de processus de génération. find a une capacité assez étendue pour modifier sa sortie imprimée en utilisant le -printf action. Le défaut -print action imprime le chemin entier, mais en utilisant -printf et une chaîne de format, il est possible de sélectionner des parties du chemin pour l'impression. Pour extraire uniquement la partie du nom de fichier du chemin sans les répertoires principaux (comme le fait basename), la chaîne de format est %f. Pour placer une nouvelle ligne après chaque nom de fichier, incluez \n comme suit:

$ 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
6
Michael Henry

TLDR; pour ceux qui viennent juste ici sur la base du title de cette question; à "Liste des sous-répertoires uniquement n niveau [s] profond": utilisez

find -maxdepth N

N est un nombre quelconque.

2
Gabriel Staples