ファイル拡張子でディレクトリを分類し、各ディレクトリの合計サイズと数を取得します。

ファイル拡張子でディレクトリを分類し、各ディレクトリの合計サイズと数を取得します。

ディレクトリ(例/home/various/:)と複数のサブディレクトリ(例:/home/various/foo//home/various/ber/)があります。/home/various/kol//home/various/whatever/

各ファイル拡張子の内容を分析して合計を表示するコマンドを実行できますか?

  • フルサイズ
  • ファイル数

端末にすべてのファイル拡張子を手動で入力したくないとしましょう。部分的には、内部のすべてのファイル拡張子を(繰り返し)知らないからです/various/

次のような出力が良いでしょう。

*.txt 23 files, 10.2MB
*.pdf 8 files, 23.2MB
*.db 3 files, 2.3MB
*.cbz 24 files, 2.3GB
*.html 2,508 files, 43.9MB
*.readme 13 files, 4KB

答え1

基本コード

duext() {

case "$1" in
  -* )
    set "./$1"
esac   

POSIXLY_CORRECT= find "${1-.}" -type f -exec du {} + | awk '
{
  sz=$1
  $1=""
  sub("^ *","")
  sub("^.*/","")
  sub("^\\.","")
  w=split($0,a,".")
  e=tolower(w==1?"*":"*."a[w])
  s[e]+=sz
  n[e]+=1
}
END {
  for (e in s) print 512*s[e]"\t"n[e]"\t"e
}'
}

使用法: duext path。デフォルト値pathはです.。この関数はsh互換性のあるシェルで実行する必要があります。

この関数は、次の形式の行を生成します。

s<tab>n<tab>e

ここでs、使用されるディスクサイズ(バイト単位)、nファイル数、e拡張子です。解析を最適化することを決めたので、要求された出力とは異なります。 「拡張子」と呼ぶのは *nix のファイル名の一部にすぎません。ファイル名にはスペースまたはタブ文字を含めることができます。e行の末尾に(スペースまたはタブを含めることができます)配置すると、他のフィールドを確実に識別できます。たとえば、次のようにサイズで簡単に並べ替えることができます。

duext /home/various/ | sort -rn -k1,1       # optionally: … | column -t

メモ:

  • パス名に改行を使用すると、誤った結果が発生します。
  • POSIXLY_CORRECT= du …使用されているディスクサイズを取得する移植可能な方法。 512バイト単位で報告されるため、コードの後半に512*s[e]あります。awkGNUはduいくつかの興味深いオプション(コード調整が必要な場合があります)を提供します--apparent-sizeawk
  • sub("^\\.","")名前の先行点を拡張区切り文字として扱わない役割を担います。実際に.nfoは拡張子nfo。これが望ましくない場合は、この行を削除してください。
  • コードは、空の拡張子(たとえばfoo.)と拡張子のない(foo)を区別します。前者はとして報告され*.、後者はとして報告されます*
  • コードは大文字と小文字を区別しません。tolower大文字と小文字を区別するには、削除してください。
  • ハードリンクによって結果が歪むことがあります。duファイルがいくつかの記録されたファイルへのハードリンクである場合は、そのファイルを無視することも、無視しないこともあります。また、(回避するために)必要な回数だけfind … -exec du {} +実行すると、ハードリンクされたファイルが同じファイルに転送されたり、転送されないことがあります。 (GNUの移植不可能なオプション)を使用するか、以下を実行して各ファイルを強制的に計算できます。ファイルごとに1つ。ハードリンク: 。ハードリンクを一度だけ安定して計算するには、別のアプローチ(GNUの単一インスタンスと?)が必要です。通常、異なる拡張子を持つハードリンクを持つことが可能です。各ハードリンクを個別に計算したい場合は問題ありませんが、1つのファイルとして計算したい場合は、割り当てられた拡張子は定義されません。duargument list too longdudu -ldudufind … -exec du {} \;du--files0-from=

カスタムフォーマット

MB何を言っているのか分からないメガバイトまたはメガバイト、私の考えは後者のようだ。次のコードは目的の形式に変換する必要があります。

yourformat() { awk '
  function human(x) {
    if (x<1000) {return x} else {x/=1000}
    s="kMGTEPZY";
    while (x>=1000 && length(s)>1)
      {x/=1000; s=substr(s,2)}
    return int(10*x+0.5)/10 substr(s,1,1)
  }
  {
    s=$1; n=$2
    $1=""; $2=""
    sub("^  ","")
    print $0" "n" file"(n==1?"":"s")", "human(s)"B"
  }'
}

(注:human(x)から抜粋この回答そして調整をしました。 )

次のように使用してください。

duext /home/various/ | yourformat

duext内部で使用されているので、awkパイプを使用してyourformat使用しますawk。通常、awk単一の関数で代わりに使用できます。それでも別のsを使用すると、たとえば、単一のシェル関数または関数間のパイプラインにawk配置できます。 (または少なくともGNUで)sort …一種のソートを実装することは可能ですが、ホイールを再発明することは意味がありません。 IMOは最初の出力を解析しやすく保つのが正しいことです。だから申請してくださいawkawkawkどのフィルタリングと書式設定は後で実行されます。

column -t使用できるようにフォーマットを改善してみましょう。 1024の買収はどうですか?

myformat() { awk '
  function human(x) {
    if (x<1000) {return x" "} else {x/=1024}
    s="kMGTEPZY";
    while (x>=1000 && length(s)>1)
      {x/=1024; s=substr(s,2)}
    return int(10*x+0.5)/10" "substr(s,1,1)"i"
  }
  {
    s=$1; n=$2
    $1=""; $2=""
    sub("^  ","")
    print $0"\t"n" file"(n==1?"":"s")"\t"human(s)"B"
  }'
}

それから:

duext /home/various/ | sort -nr -k1,1 | myformat | column -t -s "$(printf '\t')"

メモ:

  • "$(printf '\t')"タブ文字を取得する移植可能な方法です。 Bashなどの一部のシェルでは$'\t'同じことが行われます。
  • columnそれ自体は移植性がありません。
  • タブ文字を含む拡張子は書式を破損します。しかし、彼らは非常にまれです。

正直なところ、私はこのソリューションが本当に気に入って維持します。due後で使用できるようにスクリプトを作成しました。

#!/bin/sh

duext() {
}

myformat {
}

duext "${1-.}" | sort -nr -k1,1 | myformat | column -t -s "$(printf '\t')"

答え2

これは非常に興味深い問題であり、私が作ることができる最高のスクリプトは次のとおりです。

set -e
# set -x

folder=$1
counter=$(tempfile)

# List file extensions
list_extensions() {
  find "$folder" -type f |
  while read filename
  do
    basename=${filename##*/}
    ext=${basename##*.}
    echo ${ext,,}  # downcase extensions to prevent duplicates
  done |
  sort -u
}

list_extensions |
while read extension
do
  size=$(find "$folder" -type f -iname "*.$extension" -fprintf $counter . -print0 |
    du -hc --files0-from=- | tail -n 1 | sed -E 's/\s+total//')
  count=$( wc -c < $counter )
  printf "*.%-10s\t%6s files\t%10s\n" "$extension" "$count" "$size"
done

rm $counter

複雑なファイル名をサポートせずに例外が発生する可能性があり、パフォーマンスはあまり良くありませんが、うまくいきます。

出力例:

*.wma              122 files          411M
*.wpl               16 files           64K
*.xls                2 files           24K
*.xlsx               1 files           28K
*.zip                5 files          333M

関連情報