web-dev-qa-db-ja.com

フォルダ階層内のすべての個別のファイル拡張子を見つけるにはどうすればよいですか?

Linuxマシンでは、フォルダー階層を走査して、その中のすべての個別のファイル拡張子のリストを取得したいと思います。

これをシェルから実現する最良の方法は何でしょうか?

207
GloryFish

これを試してください(最良の方法かどうかはわかりませんが、動作します):

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

次のように機能します。

  • 現在のフォルダーからすべてのファイルを検索
  • ファイルの拡張子がある場合は印刷します
  • 一意のソート済みリストを作成する
312
Ivan Nevostruev

sortへのパイプは不要で、awkですべて実行できます。

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

再帰バージョン:

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

合計が必要な場合(拡張機能が表示された回数):

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

非再帰的(単一フォルダー):

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

これは このフォーラムの投稿 に基づいています。クレジットはそこにあるはずです。

34
ChristopheD

パワーシェル:

dir -recurse | select-object extension -unique

http://kevin-berridge.blogspot.com/2007/11/windows-powershell.html に感謝

23
Simon R

すべてのドットをドットで検索し、接尾辞のみを表示します。

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

すべての接尾辞が3文字であることがわかっている場合

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

または、sedを使用すると、1〜4文字のすべてのサフィックスが表示されます。 {1,4}を、接尾辞に必要な文字の範囲に変更します。

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

ミックスに独自のバリエーションを追加します。私はそれがロットの中で最も単純で、効率が大きな関心事ではないときに役立つと思います。

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

私のawkレス、sedレス、Perlレス、PythonレスPOSIX準拠の代替:

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

トリックは、最初に行を反転し、拡張子をカットすることです。
また、拡張子を小文字に変換します。

出力例:

   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

Pythonでは、空の拡張機能を含む非常に大きなディレクトリにジェネレーターを使用し、各拡張機能が表示される回数を取得します。

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

ここでたくさんの答えを試してみました。「最良の」答えも試してみました。それらはすべて、私が特に望んでいたものに足りなかった。したがって、複数のプログラムの正規表現コードに過去12時間座って、これらの回答を読んでテストする以外に、これは私が思い通りに動作するものです。

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort -u
  • 拡張子を持つ可能性のあるすべてのファイルを検索します。
  • 拡張機能のみを削除します
  • 2〜16文字のファイル拡張子のグレープ(必要に応じて数値を調整します)。これにより、キャッシュファイルとシステムファイルを回避できます(システムファイルビットはjailを検索するためです)。
  • 小文字で拡張子を印刷するにはawk。
  • 一意の値のみをソートして取り込みます。もともと私はawkの答えを試してみましたが、大文字と小文字の区別が異なるアイテムを2倍に印刷します。

ファイル拡張子の数が必要な場合は、以下のコードを使用してください

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

これらの方法は完了するまでに時間がかかり、おそらく問題を解決する最善の方法ではありませんが、機能します。

更新:@ alpha_989ごとの長いファイル拡張子により問題が発生します。これは、元の正規表現「[[:alpha:]] {3,6}」によるものです。正規表現「[[:alpha:]] {2,16}」を含むように回答を更新しました。ただし、このコードを使用するユーザーは、これらの数値が、最終出力に許可される拡張子の長さの最小値と最大値であることを認識する必要があります。その範囲外のものはすべて、出力で複数の行に分割されます。

注:元の投稿は「-3〜6文字のファイル拡張子のグレープ(ニーズに合わない場合は数字を調整するだけ)。これはキャッシュファイルとシステムファイルを回避するのに役立ちます(システムファイルビットはjailを検索します)。 」

アイデア:特定の長さのファイル拡張子を見つけるために使用できます:

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

4は、含めるファイル拡張子の長さであり、その長さを超える拡張子も検索します。

5
Shinrai

Perlを使用する別のソリューションが既にあるので:

Pythonがインストールされている場合は、次のようにすることもできます(シェルから):

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

これはまだ言及されていないと思います。

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

これまでのところ、改行を含むファイル名を適切に処理する返信はありません(これを入力しているときに入ったChristopheDを除きます)。以下はシェルのワンライナーではありませんが、動作し、かなり高速です。

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

最もシンプルで簡単な方法は

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

ChristopheDの3番目の方法で変更されています。

1
Robert

これもできます

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