1 簡單find命令
1.1 目錄結構
代碼1
$ tree
.
|-- 2.log
`-- backup
`-- 1.log
3 directories, 0 files
1.2 簡單的find命令
代碼2
$ find -path ./backup
./backup
1.3 錯誤的通配符使用
代碼3
$ mkdir backup123
$ find -path ./backup*
find: paths must precede expression
Usage: find [path...] [expression]
find命令報錯:路徑必須先表達。問題分析(引自:http://www.cnblogs.com/baibaluo/archive/2012/08/16/2642403.html):
當目錄下存在多個backup*,shell命令變成find -path backup backup123.此時,-name後面有2個匹配字符,shell報錯。
解決辦法:-path(-name)匹配的字符串已經要用單引號,或者雙引號引住。
1.4 正確的通配符寫法
代碼4
$ find -path './backup*'
./backup
./backup/1.log
./backup123
此時,命令運行正確!
2 find多條件
expr1 expr2 -o expr3 等同於 expr1 -a expr2 -o expr3.與其他語言中的與或非類似。並且是短路求值
2.1 find多條件嘗試:與
代碼5
$ find -path ./backup -name '*.log'
$
沒有任何返回結果。該語句的含義是:路徑是path,並且名字是以.log結尾的文件。顯然,並不存在。
本語句實際上是想查找,backup下所有的以.log結尾的文件。應是:
find -path './backup*' -name '*.log'
2.2 find多條件嘗試:或
代碼6
$ find -path './backup*' -o -name '*.log'
./backup
./backup/1.log
./2.log
./backup123
到這個地方,-a 和 -o的體會已經一目了然了吧。這條命令展示了在backup*下的所有文件和以.log結尾的所有文件。
3 -prune的體會
貼上這樣的幾條shell命令,請先自行體會:
代碼7
$ find -path './backup*'
./backup
./backup/1.log
./backup123
$ find -path './backup*' -prune
./backup
./backup123
3.1 prune的基本使用
-prune在man中是這麼說的
If -depth is not given, true; do not descend the current directory.
If -depth is given, false; no effect.
如果find語句中存在-depth選項,那麼-prune將會被忽略。否則,-prune將聲明不展開當前路徑。
這樣在上述的1、2條命令中,由於-prune選項的存在,致使backup路徑沒有展開。所以1.log沒有在打印列表中。
我們再次做這樣的嘗試:
代碼8
$ touch backup123/3.log
$ find -path './backup*' -prune
./backup
./backup123
$ find -path './backup*'
./backup
./backup/1.log
./backup123
./backup123/3.log
打印的結果和預期是一樣的。
按照上述2 find多條件中說道的那樣,find -path './backup*'獲得所有backup前綴的文件,然後將結果和-prune相與:其實就是判斷前者的結果中是否包含指定路徑的子文件(夾)。
3.2 prune做排除路徑用
而一般情況下prune是這樣使用的
代碼9
$ find -path './backup*' -prune -o -name '*.log' -print
./2.log
指代的意思是當前路徑除去backup*文件夾外的所有*.log文件。
3.2.1 一個問題
這樣是如願以償了,但是我們執行一下這樣的一條命令:
代碼10
$ find -path './backup*' -o -name '*.log' -print
./2.log
返回的結果一模一樣。
3.2.2 進一步剖析
這個問題我們暫且擱置不論,繼續來看這樣的2個命令:
代碼11
$ find -path './backup*' -prune -o -name '*.log'
./backup
./2.log
./backup123
$ find -path './backup*' -o -name '*.log'
./backup
./backup/1.log
./2.log
./backup123
2個結果集中只是缺少了./backup/1.log,-prune做到的只是一個收縮路徑的功能。
再繼續對比這2個命令和上面兩個命令,缺少的是一個-print.其實在man裡面有這樣的一句話"If no expression is given, the expression '-print' is used."
也就是說-print是個默認值,那麼上面2組命令實際上可以這樣看待:
輸入命令 實際命令
find -path './backup*' -o -name '*.log' find \( -path './backup*' -o -name '*.log' \) -print
find -path './backup*' -o -name '*.log' -print find \( -path './backup*' \) -o \( -name '*.log' -print \)
代碼9 和 代碼10中的片段可以理解為打印-path './backup*'為false 、 -name '*.log' 為true的find結果。
而代碼11中的片段則是將-path './backup*' -o -name '*.log'過濾後所有為true的結果都打印。
3.2.3 總結
那麼這樣看來,其實排除路徑其實是將-print放置到了-o後面作為輸出。而-path './backup*'執行過,並且返回true,單並未被打印。
那麼是不是說,其實,其實,其實-prune並沒有什麼用?
4 總結:多一點角度看find
其實可以認為
find無可避免的對指定路徑進行了全文搜索,默認情況下是深度優先搜索(只有在指定-depth的時候使用廣度優先搜索)。
find進行全文搜索以後,將結果扔到後面的過濾條件中,按照與或非的規則,逐條過濾。
最終返回值為true的item被打印了出來
試想這樣一個場景,在一個java項目中,由於項目龐大,總文件數上萬。想要找到最深2級目錄下所有的java文件。
find . -name "*.java" -maxdepth 2
find . -maxdepth 2 -name "*.java"
這樣的2條命令,顯然第二條的執行效率會快!!!-maxdepth 2 極大程度的進行了一次結果過濾。
那麼在寫find命令的時候,應該把能最大程度減小結果集的結果放到前面。