findと正規表現の問題点

-regexオプションが「パスを含むファイル名全体が正規表現にマッチするものを検索する。」とあるが、grepで使うような正規表現を書いても検索できない。
これは正規表現の種類がデフォルトでemacsになっているのが原因。

たとえばYYYY-MM-DDが含まれるファイル名を探したい。また反対にYYYY-MM-DDが含まれないファイル名を探したい。

解決方法その1

regextypeを設定する。

findのregextypeに指定できるのはemacs以外にposix-awk, posix-basic, posix-egrep, posix-extended
grepと同じにするにはregextypeposix-basicにすればよい。

※解決方法その1の注意点としては、grepと同じ種類の正規表現を使うといっても、部分一致で検索してくれるgrepとは異なり、findのregexは一番初めに書いた通り「パスを含むファイル名全体が正規表現にマッチするものを検索する」ので、正規表現がパスに完全一致しなければならないという点がある。そのため正規表現の始まりと終わりにそれぞれ ".*" を入れている。

$ find . -type f -regextype posix-basic -regex ".*[0-9]\{4\}-[0-9]\{1,2\}-[0-9]\{1,2\}.*"
./2015-06-15.log

正規表現を否定条件として使うには記号(!)をregexオプションにつける。

$ find . -type f -regextype posix-basic ! -regex ".*[0-9]\{4\}-[0-9]\{1,2\}-[0-9]\{1,2\}.*"

grepと同じでは{}等をエスケープしなければならず不便なので、egrep、grep -Eと同じ正規表現を使うためにregextypeposix-egrepにしてもいい。

$ find . -type f -regextype posix-egrep -regex ".*[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}.*"

解決方法その2

grepと組み合わせる。

grep はファイルが指定されていない場合や、ファイル名の代わりに1個のマイナス記号(-)が指定されている場合は標準入力を検索するため、findの結果をパイプで渡してあげればいい。

$ find . -type f | grep -e "[0-9]\{4\}-[0-9]\{1,2\}-[0-9]\{1,2\}" -

正規表現を否定条件として使うにはgrepのvオプションをつける。

$ find . -type f | grep -ve "[0-9]\{4\}-[0-9]\{1,2\}-[0-9]\{1,2\}" -

こちらも解決方法その1でposix-egrepを使用したのと同様にegrep、grep -Eを使用すればエスケープいらず。

$ find . -type f | grep -E "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}" -

ちなみにファイル名の検索ではなくファイルの中身を検索する場合は、xargsをパイプの直後に入れると、findの結果をgrepのFILE引数に当てはめてくれる。