web-dev-qa-db-fra.com

Comment trouver toutes les extensions de fichiers distinctes dans une hiérarchie de dossiers?

Sur une machine Linux, j'aimerais parcourir une hiérarchie de dossiers et obtenir une liste de toutes les extensions de fichiers distinctes qui s'y trouvent.

Quel serait le meilleur moyen d'y parvenir à partir d'un shell?

207
GloryFish

Essayez ceci (vous ne savez pas si c'est le meilleur moyen, mais ça marche):

find . -type f | Perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u

Cela fonctionne comme suit:

  • Trouver tous les fichiers du dossier actuel
  • Imprime l'extension des fichiers s'il y en a
  • Faire une liste triée unique
312
Ivan Nevostruev

Pas besoin du tuyau pour sort, awk peut tout faire:

find . -type f | awk -F. '!a[$NF]++{print $NF}'
45
SiegeX

Version récursive:

find . -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u

Si vous voulez des totaux (combien de fois l'extension a été vue):

find . -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort | uniq -c | sort -rn

Non récursif (dossier unique):

for f in *.*; do printf "%s\n" "${f##*.}"; done | sort -u

J'ai basé ceci sur cet article de forum , le crédit devrait y aller.

34
ChristopheD

Powershell:

dir -recurse | select-object extension -unique

Merci à http://kevin-berridge.blogspot.com/2007/11/windows-powershell.html

23
Simon R

Tout trouver avec un point et ne montrer que le suffixe.

find . -type f -name "*.*" | awk -F. '{print $NF}' | sort -u

si vous connaissez tous les suffixes ont 3 caractères puis

find . -type f -name "*.???" | awk -F. '{print $NF}' | sort -u

ou avec sed affiche tous les suffixes de un à quatre caractères. Remplacez {1,4} par la plage de caractères attendue dans le suffixe.

find . -type f | sed -n 's/.*\.\(.\{1,4\}\)$/\1/p'| sort -u
12
user224243

Ajout de ma propre variation au mélange. Je pense que c'est le plus simple du lot et peut être utile lorsque l'efficacité n'est pas une préoccupation majeure.

find . -type f | grep -o -E '\.[^\.]+$' | sort -u
7
gkb0986

Mon alternative à awk-less, sed-less, Perl less, pythonless et moins Python:

find . -type f | rev | cut -d. -f1 | rev  | tr '[:upper:]' '[:lower:]' | sort | uniq --count | sort -rn

L'astuce consiste à inverser la ligne et à couper l'extension au début.
Il convertit également les extensions en minuscules.

Exemple de sortie:

   3689 jpg
   1036 png
    610 mp4
     90 webm
     90 mkv
     57 mov
     12 avi
     10 txt
      3 Zip
      2 ogv
      1 xcf
      1 trashinfo
      1 sh
      1 m4v
      1 jpeg
      1 ini
      1 gqv
      1 gcs
      1 dv
6
Ondra Žižka

Dans Python, utilisez des générateurs pour les très grands répertoires, y compris les extensions vierges, et obtenez le nombre de fois que chaque extension apparaît:

import json
import collections
import itertools
import os

root = '/home/andres'
files = itertools.chain.from_iterable((
    files for _,_,files in os.walk(root)
    ))
counter = collections.Counter(
    (os.path.splitext(file_)[1] for file_ in files)
)
print json.dumps(counter, indent=2)
5
Andres Restrepo

J'ai essayé un tas de réponses ici, même la "meilleure" réponse. Ils ont tous manqué de ce que je recherchais. Donc, à part les 12 dernières heures passées en code regex pour plusieurs programmes et en lisant et testant ces réponses, voici ce que j’ai trouvé qui fonctionne EXACTEMENT comme je le veux.

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort -u
  • Trouve tous les fichiers pouvant avoir une extension.
  • Greps que l'extension
  • Greps pour les extensions de fichier de 2 à 16 caractères (ajustez simplement les nombres s'ils ne correspondent pas à vos besoins). Cela permet d’éviter les fichiers de cache et les fichiers système (le bit de fichier système sert à effectuer une recherche en prison).
  • Awk pour imprimer les extensions en minuscule.
  • Triez et importez uniquement des valeurs uniques. À l’origine, j’avais essayé d’essayer la réponse à awk, mais elle aurait doublé les éléments dont la sensibilité à la casse variait.

Si vous avez besoin d’un nombre d’extensions de fichier, utilisez le code ci-dessous

find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort | uniq -c | sort -rn

Bien que ces méthodes prennent un certain temps et qu'elles ne soient probablement pas la meilleure façon de résoudre le problème, elles fonctionnent.

Mise à jour: les extensions de fichier longues par @ alpha_989 poseront un problème. Cela est dû au regex original "[[: alpha:]] {3,6}". J'ai mis à jour la réponse pour y inclure l'expression régulière "[[: alpha:]] {2,16}". Cependant, toute personne utilisant ce code doit savoir que ces chiffres sont les min et max de combien de temps l'extension est autorisée pour la sortie finale. Tout ce qui est en dehors de cette plage sera divisé en plusieurs lignes dans la sortie.

Remarque: le message d'origine était "- Greps pour les extensions de fichier de 3 à 6 caractères (ajustez simplement les chiffres si elles ne correspondent pas à vos besoins). Cela évite les fichiers de cache et les fichiers système (le bit de fichier système sert à effectuer une recherche en prison). "

Idée: Peut être utilisé pour rechercher des extensions de fichier d’une longueur spécifique via:

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{4,}" | awk '{print tolower($0)}' | sort -u

Où 4 est la longueur des extensions de fichier à inclure, puis trouve également les extensions qui dépassent cette longueur.

5
Shinrai

Comme il existe déjà une autre solution utilisant Perl:

Si vous avez installé Python, vous pouvez aussi faire (depuis le shell):

python -c "import os;e=set();[[e.add(os.path.splitext(f)[-1]) for f in fn]for _,_,fn in os.walk('/home')];print '\n'.join(e)"
3
ChristopheD

Je ne pense pas que celui-ci a été mentionné pour le moment:

find . -type f -exec sh -c 'echo "${0##*.}"' {} \; | sort | uniq -c
2
Dmitry B.

Jusqu'à présent, aucune des réponses n'aborde correctement les noms de fichiers avec les nouvelles lignes (à l'exception de ChristopheD, qui est arrivé juste au moment où je tapais ceci). Ce qui suit n’est pas un one-liner Shell, mais fonctionne et est relativement rapide.

import os, sys

def names(roots):
    for root in roots:
        for a, b, basenames in os.walk(root):
            for basename in basenames:
                yield basename

sufs = set(os.path.splitext(x)[1] for x in names(sys.argv[1:]))
for suf in sufs:
    if suf:
        print suf
2
user25148

Je pense que la manière la plus simple et directe est

for f in *.*; do echo "${f##*.}"; done | sort -u

C'est modifié sur la 3ème voie de ChristopheD.

1
Robert

tu pourrais aussi faire ça

find . -type f -name "*.php" -exec PATHTOAPP {} +
0
jrock2004