find コマンドで全てのファイルにマッチしない!

Linuxでファイル検索する場合の基本コマンドに、「find」があります。ファイル名に含まれる文字列の一部を検索したりできるのですが、検索条件をちょっと間違えるだけで、目的のファイルが見つからなく(マッチしなく)なるので、注意が必要です。

例えば、以下の構成のディレクトリとファイルがあるとします。

# tree -F root
root/
└── my-dir/
    ├── dir1/
    │   └── memo2.txt
    ├── dir2/
    │   └── memo2.txt
    └── memo.txt

この時、拡張子が .txt のファイルを探したいとします。root というディレクトリ内で以下のfindを実行してみます。

# cd root/
# find . -name *txt
./my-dir/dir2/memo2.txt
./my-dir/memo.txt
./my-dir/dir1/memo2.txt

目的の .txt 拡張子のファイルが全てマッチしました。

では、my-dir ディレクトリの中で同じコマンドを実行するとどうなるでしょうか?

# cd my-dir/
# find . -name *txt
./memo.txt

このように、memo.txt しかマッチしなくなりました。なぜ、このような事象が起きてしまうのでしょうか? 実は、今回このコマンドを実行しているシェル(bash)の仕様が関係しているのです。

bash でのアスタリスク 「* 」はワイルドカード展開を意味します。つまり、カレントディレクトリに *txt にマッチするファイルがあると、コマンド実行前にそのファイル名に置き換えられるわけです。実際にコマンドを叩いて試してみます。

上記ディレクトリ構成で、root ディレクトリ内で、echo *txt を実行してみます。

# cd root
# echo *txt
*txt

my-dir ディレクトリでも同様にechoを実行してみます。

# cd my-dir/
# echo *txt
memo.txt

このように、root ディレクトリ内には、*txt にマッチするファイルがないので、アスタリスクが置き換わらず、echo 出力に *txt と表示されましたが、my-dir ディレクトリ内には、memo.txt というファイルがあるので、echo出力は、memo.txt に置き換わってしまいました。

つまり、my-dir 内でfindを実行した場合、

# find . -name *txt

# find . -name memo.txt

を実行していることになり、結果、memo.txt にしかマッチしないという悲劇を生み出すわけです。ここまで理解できれば、対処方法は簡単です。シェルにアスタリクスを処理させなければよいわけです。例えば、アスタリクスをエスケープ(\)すると、マッチするようになります。

# find . -name \*txt
./dir2/memo2.txt
./memo.txt
./dir1/memo2.txt

ただ、この方法は面倒だと思うので、シングルクォートで囲む方が一般的だと思います。

# find . -name '*txt'
./dir2/memo2.txt
./memo.txt
./dir1/memo2.txt

以上findのちょっとしたtipsでした。

find でファイル名の文字列検索時は、
必ずシングルクォートで囲みましょう!

タイトルとURLをコピーしました