295

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

シェルからこれを達成するための最良の方法は何でしょうか?

4

17 に答える 17

418

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

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

次のように機能します。

  • 現在のフォルダからすべてのファイルを検索
  • ファイルの拡張子があれば印刷します
  • 一意のソート済みリストを作成する
于 2009-12-03T19:21:46.710 に答える
74

パイプの必要はありませんsort、awkはそれをすべて行うことができます:

find . -type f | awk -F. '!a[$NF]++{print $NF}'
于 2011-08-24T05:21:12.500 に答える
55

再帰バージョン:

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

私はこれをこのフォーラムの投稿に基づいています、クレジットはそこに行くべきです。

于 2009-12-03T19:38:02.323 に答える
40

私のawk-less、sed-less、Perl-less、Python-less 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
于 2019-03-23T18:37:54.427 に答える
38

パワーシェル:

dir -recurse | select-object extension -unique

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

于 2010-04-23T14:18:42.800 に答える
13

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

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
于 2009-12-03T21:47:59.100 に答える
11

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

find . -type f | grep -oE '\.(\w+)$' | sort -u
于 2013-07-15T05:59:06.233 に答える
9

私はここでたくさんの答えを試しましたが、「最良の」答えも試しました。それらはすべて、私が具体的に求めていたものには及ばなかった。したがって、過去12時間に複数のプログラムの正規表現コードを使用し、これらの回答を読んでテストしたことに加えて、これが私が思いついたものであり、まさに私が望むように機能します。

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

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

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は含めるファイル拡張子の長さであり、その長さを超える拡張子も検索します。

于 2014-05-26T18:45:50.370 に答える
5

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)
于 2012-08-24T19:17:28.120 に答える
4

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)"
于 2009-12-04T08:27:53.573 に答える
2

これまでのところ、改行を含むファイル名を適切に処理する応答はありません(これを入力しているときに入力された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
于 2009-12-04T08:35:28.977 に答える
2

最もシンプルでわかりやすい方法は

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

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

于 2018-02-13T08:21:45.380 に答える
2

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

find . -type f -exec sh -c 'echo "${0##*.}"' {} \; | sort | uniq -c
于 2018-05-21T23:01:17.007 に答える
2

別の方法:

find . -type f -name "*.*" -printf "%f\n" | while IFS= read -r; do echo "${REPLY##*.}"; done | sort -u

ドロップすることもできますが-name "*.*"、これにより、ある種の拡張子を持つファイルのみを処理することが保証されます。

これ-printffind、bashではなく印刷物です。-printf "%f\n"ファイル名のみを出力し、パスを削除します(そして改行を追加します)。

次に、文字列置換を使用して、。を使用して最後のドットまでを削除し${REPLY##*.}ます。

$REPLYこれは単にreadの組み込み変数であることに注意してください。次の形式で独自のものを使用することもできwhile IFS= read -r fileます。ここでは、$fileが変数になります。

于 2021-05-31T15:18:57.407 に答える
1

受け入れられた答えはREGEXを使用しており、REGEXでエイリアスコマンドを作成することはできません。シェルスクリプトに入れる必要があります。私はAmazon Linux 2を使用しており、次のことを行いました。

  1. 受け入れられた回答コードを使用してファイルに入れました:

    sudo vim find.sh

このコードを追加します:

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

次のように入力してファイルを保存します。 :wq!

  1. sudo vim ~/.bash_profile

  2. alias getext=". /path/to/your/find.sh"

  3. :wq!

  4. . ~/.bash_profile

于 2020-04-04T13:02:38.330 に答える
0

あなたもこれを行うことができます

find . -type f -name "*.php" -exec PATHTOAPP {} +
于 2013-03-25T16:12:15.643 に答える
0

シンプルで速いと思いました...

   # find . -type f -exec basename {} \; | awk -F"." '{print $NF}' > /tmp/outfile.txt
   # cat /tmp/outfile.txt | sort | uniq -c| sort -n > tmp/outfile_sorted.txt
于 2020-02-20T14:28:44.337 に答える