すべてのサブディレクトリを調べて、それらに含まれるファイル(再帰なし)の数を報告する必要があります。
directoryName1 numberOfFiles
directoryName2 numberOfFiles
これは安全で移植可能な方法でそれを行います。奇妙なファイル名で混乱することはありません。
for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \; | wc -l && echo $f; done
最初にファイル数を出力し、次にディレクトリ名を別の行に出力することに注意してください。 OPのフォーマットを維持したい場合は、さらにフォーマットする必要があります。
for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \;|wc -l|tr '\n' ' ' && echo $f; done|awk '{print $2"\t"$1}'
関心のある特定のサブディレクトリセットがある場合は、*
をそれらに置き換えることができます。
なぜこれが安全なのですか?(したがって、スクリプトに値する)
ファイル名には、/
以外の任意の文字を含めることができます。シェルまたはコマンドによって特別に処理される文字がいくつかあります。それらには、スペース、改行、ダッシュが含まれます。
for f in *
構文を使用すると、内容に関係なく、各ファイル名を安全に取得できます。
変数にファイル名を入れても、find $f
のようなことは避けなければなりません。 $f
にファイル名-test
が含まれている場合、find
は指定したオプションについて文句を言うでしょう。これを回避する方法は、名前の前に./
を使用することです。この方法でも同じ意味ですが、ダッシュで始まっていません。
改行とスペースも問題です。 $f
にファイル名として「hello、buddy」が含まれている場合、find ./$f
はfind ./hello, buddy
です。 find
に./hello,
とbuddy
を見るように指示しています。それらが存在しない場合、文句を言い、./hello, buddy
を検索することはありません。これは簡単に回避できます。変数を引用符で囲んでください。
最後に、ファイル名には改行を含めることができるため、ファイル名のリストで改行を数えることはできません。改行を含むすべてのファイル名に対して追加のカウントが得られます。これを回避するには、ファイルのリストの改行を数えないでください。代わりに、単一のファイルを表す改行(またはその他の文字)を数えます。これが、find
コマンドに-exec echo \;
ではなく-exec echo {} \;
があるだけの理由です。ファイルを集計する目的で、新しい行を1行だけ印刷したいと思います。
標準のLinuxソリューションを探していると仮定すると、これを達成する比較的簡単な方法はfind
を使用することです。
find dir1/ dir2/ -maxdepth 1 -type f | wc -l
ここで、find
は、指定された2つのサブディレクトリを-maxdepth
の1に移動します。これにより、再帰が防止され、改行で区切られたファイル(-type f
)のみが報告されます。次に、結果をwc
にパイプして、それらの行の数をカウントします。
「再帰なし」とは、directoryName1
にサブディレクトリがある場合、サブディレクトリ内のファイルをカウントしないことを意味しますか?もしそうなら、ここに示されたディレクトリ内のすべての通常のファイルを数える方法があります:
count=0
for d in directoryName1 directoryName2; do
for f in "$d"/* "$d"/.[!.]* "$d"/..?*; do
if [ -f "$f" ]; then count=$((count+1)); fi
done
done
-f
テストは2つの機能を実行することに注意してください:上記のグロブの1つに一致するエントリが通常のファイルであるかどうかをテストし、エントリが一致したかどうかをテストします(グロブの1つが何にも一致しない場合、パターンそのままです¹)。タイプに関係なく、指定されたディレクトリのすべてのエントリをカウントする場合は、-f
を-e
に置き換えます。
Kshには、ドットファイルにパターンを一致させる方法と、ファイルがパターンに一致しない場合に空のリストを生成する方法があります。したがって、kshでは、次のような通常のファイルをカウントできます。
FIGNORE='.?(.)'
count=0
for x in ~(N)directoryName1/* ~(N)directoryName2/*; do
if [ -f "$x" ]; then ((++count)); fi
done
またはすべてのファイルは次のようになります:
FIGNORE='.?(.)'
files=(~(N)directoryName1/* ~(N)directoryName2/*)
count=${#files}
Bashには、これを簡単にするためのさまざまな方法があります。通常のファイルを数えるには:
shopt -s dotglob nullglob
count=0
for x in directoryName1/* directoryName2/*; do
if [ -f "$x" ]; then ((++count)); fi
done
すべてのファイルを数えるには:
shopt -s dotglob nullglob
files=(directoryName1/* directoryName2/*)
count=${#files}
いつものように、zshではさらに単純です。通常のファイルを数えるには:
files=({directoryName1,directoryName2}/*(DN.))
count=$#files
すべてのファイルをカウントするには、(DN.)
を(DN)
に変更します。
¹ 各パターンはそれ自体と一致することに注意してください。一致しない場合、結果がオフになる可能性があります(たとえば、数字で始まるファイルを数える場合、for x in [0-9]*; do if [ -f "$x" ]; then …
を実行できません。これは、[0-9]foo
というファイルが存在する可能性があるためです。 )。
count script 、 Shawn's answer 、および改行を含むファイル名でも使用可能な形式で1行に出力されるようにするBashトリックに基づいています。
for f in *
do
if [ -d "./$f" ]
then
printf %q "$f"
printf %s ' '
find "$f" -maxdepth 1 -printf x | wc -c
fi
done
printf %q
は、引用符で囲まれたバージョンの文字列、つまりBashスクリプトに入力して、(潜在的に)改行やその他の特殊文字を含むリテラル文字列として解釈できる単一行の文字列を出力します。たとえば、echo -n $'\tfoo\nbar'
とprintf %q $'\tfoo\nbar'
をご覧ください。
find
コマンドは、ファイルごとに1文字を出力し、行を数えるのではなくそれらを数えるだけで機能します。
find
、echo
、ls
、wc
、xargs
を使用して結果を取得する「ブルートフォース」っぽい方法は次のとおりですおよびawk
。
find . -maxdepth 1 -type d -exec sh -c "echo '{}'; ls -1 '{}' | wc -l" \; | xargs -n 2 | awk '{print $1" "$2}'