ディレクトリ内の各拡張子のファイル数を見つける


10

ディレクトリ内の各拡張子のファイルと、拡張子のないファイルの数を数えたい。

私はいくつかのオプションを試しましたが、実用的な解決策はまだ見つかりません:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -cオプションですが、ファイル拡張子がない場合は機能しません。拡張子のないファイルの数を知る必要があります。

  • また、配列に検索ループを試みて結果を合計しましたが、現時点では、そのコードは宣言されていない変数エラーをスローしますが、ループの外側のみをスローします。

    declare -a arr
    arr=()
    echo ${arr[@]}
    

    これにより、宣言されていない変数がスローされます。また、検索ループが完了するとスローされます。

回答:


10
find "$path" -type f | sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' | LC_COLLATE=C sort | uniq -c

説明:

  • find "$path" -type f "$path"フォルダ上のすべてのファイルの再帰的なリストを取得します。
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' 正規表現:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ 拡張子のないすべてのファイルを(なし)に置き換えます。
    • s/.*\.// 残りのファイルの拡張子を取得します。
  • LC_COLLATE=C sort シンボルを一番上にして、結果を並べ替えます。
  • uniq -c 繰り返されるエントリの数を数えます。

9

Pythonの使用:

import os
from collections import Counter
from pprint import pprint

lst = []
for file in os.listdir('./'):
        name, ext = os.path.splitext(file)
        lst.append(ext)

pprint(Counter(lst))

出力:

Counter({'': 7,
         '.png': 4,
         '.mp3': 3,
         '.jpg': 3,
         '.mkv': 3,
         '.py': 1,
         '.swp': 1,
         '.sh': 1})

ext = [ f.split('.')[-1] for f in os.listdir('./') ] Thatllのようにリストを理解することで、おそらく数行を短くし、おそらくPythonicを増やすことができます。
Sergiy Kolodyazhnyy

提案をありがとう、私はそれを
できるだけ

1
明快さは美徳です:)特にコードとエンジニアリングのドキュメントに関しては。
Sergiy Kolodyazhnyy 2018

6

あなたがGNU awkを持っているなら、あなたは次のようなことをすることができます

printf '%s\0' * | gawk 'BEGIN{RS="\0"; FS="."; OFS="\t"} 
  {a[(NF>1 ? $NF : "(none)")]++} 
  END{for(i in a) print a[i],i}
'

つまり、最後に.区切られたフィールドをキーとする連想配列、または(none)拡張子がない場合などの任意の固定文字列を作成/増分します。

mawkは、nullバイトのレコード区切り文字を許可していないようですmawk。ファイル名の改行を処理する必要がないと確信している場合は、デフォルトの改行区切り文字を使用できます。

printf '%s\n' * | mawk 'BEGIN{FS="."; OFS="\t"} {a[(NF>1 ? $NF : "(none)")]++} END{for(i in a) print a[i],i}'

5

基本的な/bin/sh場合やbashタスクでさえ少し難しい場合がありますが、他の回答でわかるように、集計データを操作できるツールは、そのようなタスクを特に簡単に処理できます。そのようなツールの1つがsqliteデータベースです。

sqliteデータベースを使用する非常に単純なプロセスは、.csvファイル名と拡張子の2つのフィールドを持つファイルを作成することです。後でsqlite単純な集計ステートメントCOUNT()を使用しGROUP BY extて、拡張子フィールドに基づいてファイルのカウントを実行できます

$ { printf "file,ext\n"; find -type f -exec sh -c 'f=${1##*/};printf "%s,%s\n" "${1}" "${1##*.}"' sh {} \; ; }  > files.csv
$ sqlite3 <<EOF
> .mode csv
> .import ./files.csv files_tb
> SELECT ext,COUNT(file) FROM files_tb GROUP BY ext;
> EOF
csv,1
mp3,6
txt,1
wav,27

files_tbテーブルが参照されていると思いますが、テーブルの列がどこにも定義されていません。
WinEunuuchs2Unix 2018

@ WinEunuuchs2Unixそれらはcsvファイル自体で定義されています。それが最初のprintfものです。SQLiteはデフォルトでcsvファイルの最初の行を列名として扱います。
Sergiy Kolodyazhnyy

1
非常に印象的!+1
WinEunuuchs2Unix

5

オプションの場合はPowerShellを使用する:

Get-ChildItem -File | Group-Object Extension -NoElement

エイリアスを使用して、またはより短く:

ls -file | group -n Extension

1
うわー!素晴らしい最初の答え!LinuxにPowerShellが存在することさえ知りませんでした... +1
Fabby

2
ありがとう。それはクロスプラットフォームとオープンソースでしばらく存在していましたが、SOとSUには、Windowsのシェルスクリプトに関する質問に「まあ、cygwinをインストールしてbashを使用して、次のようにすることができます。 「それで、私はLinux SEサイトに対して同じことをWindowsから始まったツールで行うのをためらっていました。しかし、これは、冗長性に関する古い議論を招くことなく、PowerShellの強みを非常にうまく示す素晴らしいタスクでした。
Joey
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.