歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> 再看一眼find--find使用中遇到的問題分析

再看一眼find--find使用中遇到的問題分析

日期:2017/3/1 12:23:44   编辑:關於Linux
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命令的時候,應該把能最大程度減小結果集的結果放到前面。
Copyright © Linux教程網 All Rights Reserved