【linux】findコマンドで「.svnディレクトリの中以外」
問題
findコマンドでファイルを検索するとき、.git ディレクトリや .svn ディレクトリや *.bak ファイルや *.log ファイルなどは対象外にしたい。
「*.phpファイル で .svnディレクトリの中のファイルではない」などを表現できる?
答え
findコマンドの書式を簡単に書くと、以下のとおり。
find オプション 探す場所 式 式 式 ...
後ろに続くものはすべて式。
式は判定条件(-name, -type, -mtime …)であったり、アクション系のオプション(-print、-delete、-exec …)であったり、動作を変更するオプション(-depth …)であったりするが、すべて戻り値がある。
プログラムのif文の条件のように、「式 and 式 and 式 and …」なら、左から各式が真を返す限り評価される。or(-o)結合で「式 or 式 or 式 or …」なら、左からいずれかの式で真が返ってくるまで評価される。
先に評価したい式があれば、計算式のように括弧()で囲む。括弧はシェルにとって特別な意味を持っているので、クォートする必要がある。\( ...... \)
となる。
-print
を省略しても、検索したファイルを画面に表示してくれる環境が多いが、その動作は保障されているわけではないので、-print を書く癖を付けておいて損はしない。ちなみに -printは常に真を返す。
以上を把握していれば、以下の例が理解可能だと思う。
用例
あるディレクトリ以下のファイルを表示する。
$ find /tmp/test -print /tmp/test /tmp/test/test1 /tmp/test/test1/test2.php /tmp/test/test1/test.txt /tmp/test/test1/test.html /tmp/test/test1/test.php
あるディレクトリ以下から、末尾が.phpの名前のファイルを見つけて表示する。
$ find /tmp/test -name "*.php" -print /tmp/test/test1/test2.php /tmp/test/test1/test.php
あるディレクトリ以下から、末尾が.phpの名前のファイルを表示して、表示する(なんの役に立つのかは別として)。
$ find /tmp/test -name "*.php" -print -print /tmp/test/test1/test2.php /tmp/test/test1/test2.php /tmp/test/test1/test.php /tmp/test/test1/test.php
あるディレクトリ以下から、末尾が.phpの名前のファイルを削除する。その後の状態を確認する。
$ find /tmp/test -name "*.php" -delete $ find /tmp/test -print /tmp/test /tmp/test/test1 /tmp/test/test1/test.txt /tmp/test/test1/test.html
あるディレクトリ以下から、末尾が.phpの名前のファイルを表示してから削除する。削除したファイルを確認できる。ディレクトリも空であれば-deleteで削除できる。
$ find /tmp/test -name "*.php" -print -delete /tmp/test/test1/test2.php /tmp/test/test1/test.php
and結合の方がor結合より強いので、以下のように書くと、(-name “*.php” -print) と (-name “*.html” -print) が先に評価される。拡張子がphpのファイルと拡張子がhtmlのファイルがいずれも表示される。
$ find /tmp/test -name "*.php" -print -o -name "*.html" -print /tmp/test/test1/test2.php /tmp/test/test1/test.html /tmp/test/test1/test.php
拡張子がphpのファイルと拡張子がhtmlのファイルを表示したいときに以下のように書くと、(-name “*.php”) と (-name “*.html” -print) が先に評価されるので、表示されるのはhtmlファイルのみとなる。
$ find /tmp/test -name "*.php" -o -name "*.html" -print /tmp/test/test1/test.html
拡張子がphpのファイルと拡張子がhtmlのファイルを表示したいときの別な書き方はこう。括弧は演算子なので、括弧の前後にスペースは必要。
$ find /tmp/test \( -name "*.php" -o -name "*.html" \) -print /tmp/test/test1/test2.php /tmp/test/test1/test.html /tmp/test/test1/test.php
問題の「ファイルで、パス中に .svnを含まないものを表示する」のは、以下のように書ける。否定は !だが、これもシェルにとって意味がある文字なのでエスケープして \!と書く。
$ find . -type f \! -path '*.svn*'
条件をちょっと変えて、ここ30日変更がないファイルを表示する例。
$ find . -mtime +30 -print
and と or の動きを見る例
and結合だと、falseが登場した時点で評価が終了するため -printが評価されない → 何も表示されない。
$ find . -false -print
or結合だと、trueが登場した時点で評価が終了するため -printが評価されない → 何も表示されない。
$ find . -false -o -true -o -print
全部表示される(find . -print となんら変わりない)。
$ find . -false -true -o -true -false -o -print
最初に -print(アクション系だが真を返す)があると、後ろに何があっても、とりあえずすべてのファイルが表示がされる。
$ find . -print -false -true -false
参考
http://linuxjm.sourceforge.jp/html/GNU_findutils/man1/find.1.html
コメント