スクリプトにエラーがあります。コマンド find はスペース文字を含むフォルダをスキップします。

スクリプトにエラーがあります。コマンド find はスペース文字を含むフォルダをスキップします。

ディレクトリ (およびサブディレクトリ) 内のファイルをカウントするスクリプトが必要です。次のスクリプトを取得し、必要に応じて変更しました。

スペース文字を含むフォルダーを除いて、期待どおりに動作します。引用符がどこかに欠けていると確信していますが、まだ原因がわかりません。

追加情報

  • Linux 2.6.22.19-0.4-default (このサーバーはもはや実稼働環境ではありません。)
  • GNU find バージョン 4.2.31
  • ディレクトリの名前を変更できません。

ディレクトリ構造の例

.
..
01_infos
02_sent
03_inbox
04_public and private
197.
145.
329.
13.

脚本

#!/bin/bash
# Write a script that will count the number of files in each of your subdirectories.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------

START=$HOME

# change your directory to command line if passed
# otherwise use home directory
[ $# -eq 1 ] && START=$1 || :

if [ ! -d $START ]
then
        echo "$START not a directory!"
        exit 1
fi

# use find command to get all subdirs name in DIRS variable
DIRS=$(find "$START" -type d)

# loop thought each dir to get the number of files in each of subdir
for d in $DIRS
do
        echo "$d directory has $(find "$d" -maxdepth 1 -regex '.*\.' -type f | wc -l) files" || :
done

出力

./01_infos directory has 1 files
./02_sent directory has 9 files
./03_inbox has 4 files
find: ./04_public: No such file or directory

答え1

二重引用符が抜けています(変数置換$fooとコマンド置換は常に二重引用符で囲みます$(foo)ただし、なぜそれらを安全にオフにできるのか、またなぜそれらをオフにする必要があるのか​​がわかっている場合は別です。しかし、問題はそれだけではありません。

if [ ! -d $START ]

であるべきですif [ ! -d "$START" ]

DIRS=$(find "$START" -type d)

この時点で、 にDIRSは開始ディレクトリとそのサブディレクトリの名前が再帰的に含まれ、間には改行が入ります。したがって、改行を含むディレクトリ名がある場合は負けです。どの改行がディレクトリ名から来たもので、どれが区切り文字だったのかを知ることは不可能です。ファイル名に改行がないことが分かっている場合は、 の出力を解析できますfindが、どうすればわかるのでしょうか。

ちなみに、$(…)これは変数の割り当てであり、割り当て内の置換は暗黙的に保護されているため、ここでは二重引用符を使用しなくても問題ありません。ただし、 はexport DIRS=$(…)同様に保護されていないことに注意してください。シェル スクリプトに精通していて、スクリプトを保守するすべての人がシェル スクリプトに精通している場合を除き、引用符を使用することをお勧めします。

for d in $DIRS

ここで失敗します。$DIRS単語に分割したいので二重引用符は使用できませんが、$DIRSすべての要素が連結されるため二重引用符が必要であり、引用符を付けずに残しておくとスペース内のファイル名が区切り文字になります。


通常、 を使用する場合はfind、 オプションを使用して処理コマンドを呼び出すようにする必要があります-exec。ファイル名を厳密に制御していない限り、 の出力を解析しないでくださいfind。あいまいです。

find "$START" -type d -exec sh -c '
    echo "$0 directory has $(find "$0" -maxdepth 1 -regex ".*\\." -type f -printf \\n | wc -l) files whose name ends with ."
' {} \;

埋め込みfindコマンドで再度注意してください。 の出力を解析するとfind、ファイル名に改行が含まれているとカウントがオフになります。

答え2

これだけはどうでしょうか?

find . -type d -exec sh -c '/bin/echo -n "{}"; find "{}" -maxdepth 1 -regex ".*\." -type f | wc -l; ' \;

出力はそれほど甘くはありませんが、スクリプトは必要なく、スペースやその他の非英数字文字を含むディレクトリでも機能します。

答え3

典型的な引用符の間違いがあります。 for ループを次のように修正してください。

for d in "$DIRS"

あるいは、出力を直接入力することもできますfind。例:

find "$START" -type d | while read d
do # and so on...

余談ですが、この|| :ビットは完全に冗長であり、echo戻り値は常に 0 になります。

関連情報