find 是一個資深的 UNIX 工具。它的功能在於遞迴掃描一個或多個目錄,從中尋找匹配指定條件的檔案。儘管此工具非常有用,但文法卻十分複雜,使用的時候也需要多多練習。最普通的文法是這樣的:
如果您不指定任何目錄,find 將會尋找目前的目錄。如果您不指定條件,則條件相當於“true”,這樣會把全部檔案都找出來。選項、條件和動作的設定十分繁多,我們在這裡只會提到其中的少數幾個。首先,讓我們來看看著幾個選項:
-xdev:不在其它檔案系統的目錄中搜尋。
-mindepth <n>:搜尋檔案時至少要深入到指定目錄的第 n 層子目錄。
-maxdepth <n>:搜尋檔案時最多深入到指定目錄的第 n 層子目錄。
-follow:如果符號連結到目錄,則跟隨符號連結進入。預設情況下,find 不跟隨連結。
-daystart:當使用與事件相關的測試時(見下文),將當天的開始時間作為時間戳記,而不是預設值(從目前時間倒退24個小時)。
條件可以是一個或多個原子測試。這是一些有用的測試:
-type <檔案類型>:搜尋給定類型的檔案。檔案類型可以是以下之一:f(普通檔案)、d(目錄)、l(符號連結)、s(通訊端)、b(塊模式檔案)、c(字元模式檔案)或p(具名管道)。
-name <模式>:尋找檔案名稱與給定模式比對的檔案。使用此選項,模式將被看作shell 全域模式(參見“Shell
萬用字元”一節)。
-iname <模式>:與 -name 類似,但不區分大小寫。
-atime <n>、-amin <n>:尋找上次訪問時間在 n 天前(-atime)或 n 分鐘前(-amin) 的檔案。您還可以指定 <+n> 或 <-n>,這代表要搜尋訪問時間在至多或者至少 n 天/分鐘前的檔案。
-anewer <檔案>:尋找上次訪問時間晚於檔案的檔案。
-ctime <n>、-cmin <n>、-cnewer <file>:與 -atime、-amin 和 -anewer 相同,但比較的是檔案上次修改的時間。
-regex <模式>:與 -name 相同,但模式將被看作Regex。
-iregex <pattern>:與 -regex 相同,但不區分大小寫。
可供選擇的設定還有很多,請參看 find(1) 中的詳情。要進行組合測試,您可以使用以下格式之一:
<c1> -a <c2>:如果 c1 和 c2 都為 true,則結果為 true;-a 是隱含的,也就是說如果您想要同時測試 c1、c2 和 c3 三個條件,只需輸入<c1>
<c2> <c3>。
<c1> -o <c2>:如果 c1 或 c2 中至少有一個是 true,則結果為 true。請注意 -o 的優先順序低於 -a,因此如果您想要匹配滿足條件 c1 或 c2,且滿足 c3 的檔案,您就需要使用括弧,即(
<c1> -o <c2> ) -a <c3>。您還必須對括弧進行轉碼,否則括弧將被 shell 加以解釋!
-not <c1>:測試 c1 的相反結果,因此如果 c1 是 false 的話,-not <c1> 就是 true。
最後,您可以為找到的檔案指定一個動作。最常用的有:
-print:僅僅將每個檔案的名稱列印在標準輸出。這是預設動作。
-ls:對每個找到的檔案以 ls -ilds 的格式列印在標準輸出上。
-exec <命令列>:對每個找到的檔案依次執行命令列。命令列必須以分號(;)結尾,您還必須對其進行轉碼,以防 shell 對其進行解釋;檔案位置以 {} 進行標記。請參看用法的例子。
-ok <命令>:與 -exec 相同,但對每個命令都請求使用者確認。
要理解這些選項和參數最好的方法是執行一些例子。現在,您想要在 /usr/share 目錄中尋找全部目錄,只需輸入:
假設您有 HTTP 伺服器,而您所有的 HTML 檔案都存在 /var/www/html,該目錄也是您的目前的目錄。您想要尋找一個月來沒有編輯過的全部檔案。由於您擁有來自不同作者的頁面,所以有些檔案的副檔名是 html,有些檔案的副檔名是 htm。您想要將這些檔案連結在目錄 /var/www/obsolete 中。您應該輸入[17]:
find \( -name "*.htm" -o -name "*.html" \) -a -ctime -30 \-exec ln {} /var/www/obsolete \; |
這個例子看起來有點複雜,我們會進行詳細解釋。這裡所用的條件是:
\( -name "*.htm" -o -name "*.html" \) -a -ctime -30 |
它所完成的功能正是我們想要的:它會找到檔案名稱以 .htm 或 .html“\( -name "*.htm" -o
-name "*.html" \)” 結尾的檔案,而且(-a) 在最近的三十天內沒有修改過,這大概是一個月(-ctime -30)。請額外注意括弧:這裡的括弧時必需的,因為 -a 的優先順序較高。如果沒有括弧的話,將會找到所有以 .htm 結尾的檔案,以及所有一個月以來沒有修改過且以 .html 結尾的檔案。這顯然不是我們所需要的結果。您還應該注意括弧需要在
shell 中加以轉碼:如果我們寫的是 ( .. ),而不是 \( .. \),那麼 shell 就會對括弧進行解釋,並且試圖在子 shell 中執行 -name "*.htm" -o -name "*.html"……另外一種解決方案是將括弧放在雙引號或單引號中,但是我們更願意在此使用反斜線,因為這裡只有一個字元。
最後,還要對每個檔案執行這個命令:
-exec ln {} /var/www/obsolete \; |
這裡,您仍然需要對分號(;)進行轉碼,否則 shell 會將其解釋為命令分隔字元。如果您忘記了進行轉碼,find 將會抱怨說 -exec 缺少一個參數。
最後一個例子:您有一個非常大的目錄(/shared/images),其中包含各種映像。通常,您會使用 touch 命令更新此目錄中名為 stamp 的檔案的時間,這樣您就會有一個可參考的時間。您想要找到比 stamp 檔案新的所有 JPEG 映像,但是您的映像來源各不相同,副檔名有 jpg、jpeg、JPG 以及 JPEG。您還想要不在 old 目錄中搜尋。不僅如此,您還想要將此檔案清單發送給您,而您的使用者名稱是 li_si:
find /shared/images -cnewer \ /shared/images/stamp \ -a -iregex ".*\.jpe?g" \ -a -not -regex ".*/old/.*" \ | mail li_si -s "New images" |
當然,如果您每次都要重複輸入的話,這個命令確實沒什麼用。您可能會想要定時執行該命令。要定時運行命令,最簡單的方法就是使用下一節介紹的 cron 精靈。