1. 程式人生 > >Linux Find 命令精通指南

Linux Find 命令精通指南

Linux find 命令是所有 Linux 命令中最有用的一個,同時也是最混亂的一個。它很難,因為它的語法與其他 Linux 命令的標準語法不同。但是,它很強大,因為它允許您按檔名、檔案型別、使用者甚至是時間戳查詢檔案。使用 find 命令,您不但可以找到具這些屬性任意組合的檔案,還可以對它找到的檔案執行操作。

本文的目的是,通過概述 find 命令的用途和潛能,簡化該命令的學習和使用。同時,它將針對 find 命令的某些最強大但最混亂的方面提供一個基本的指南和參考。

[注意:本文使用的 find 版本是 GNU 版本,因此,某些細節可能與其他版本的 find 有所不同。]

基本格式

開始之前,我們先來看一下 

find 命令的基本結構:

find   start_directory  test  options   criteria_to_match
action_to_perform_on_results
                          
在以下命令中,find 將開始在當前目錄(用“.”表示)中查詢任何副檔名為“java”的檔案:
find . -name  "*.java"   

下面是該命令所找到的命令的縮略清單:

find . -name  "*.java"
./REGEXPvalidate/src/oracle/otnsamples/plsql/ConnectionManager.java
./REGEXPvalidate/src/oracle/otnsamples/plsql/DBManager.java
..

[注意:如果您從本文剪下並貼上來執行該 find 命令,您可能需要使用自己的鍵盤替換雙引號 (“”) 才能得出正確的結果。]

以下命令將執行相同的操作。在這兩種情況下,您都需要對萬用字元進行轉義以確保它傳遞到 find 命令並且不由 shell 解釋。因此,請將您的搜尋字串放到引號裡,或者在它前面加上反斜線:

find . -name  /*.java

儘管 find 的所有引數均為可選,但是如果您未指定從哪裡開始搜尋,搜尋預設將在當前目錄中開始。如果您不指定要匹配的測試連線、選項或值,您的結果將不完整或者無區別。
 
執行以下三個 find 命令將得出同樣的結果 — 當前目錄和所有子目錄中的所有檔案(包括隱藏檔案)的完整清單:

find 
find .
find . -print

這類似於執行一個帶 -la 選項的 ls 命令。如果您希望上述命令的輸出包含完整的路徑名(或許是為了備份),您將需要指定起始目錄的完整路徑:

find /home/bluher -name /*.java
/home/bluher/plsql/REGEXPvalidate/src/oracle/otnsamples/plsql/ConnectionManager.java
/home/bluher/plsql/REGEXPvalidate/src/oracle/otnsamples/plsql/DBManager.java/
...

您還可以在搜尋字串中指定多個起始目錄。如果以具有相應許可權的使用者身份執行,以下命令將下到 /usr、/home /tmp 目錄查詢所有 jar 檔案:

find /usr /home  /tmp -name "*.jar"

但是,如果您沒有相應的許可權,您在開始瀏覽許多系統目錄時將生成錯誤訊息。以下是一個示例:

find:  /tmp/orbit-root: Permission denied

您可以通過附加您的搜尋字串來避免混亂的輸出,如下所示:

find /usr /home  /tmp -name "*.jar" 2>/dev/null

這會將所有錯誤訊息傳送到空檔案,因此提供清理器輸出。

預設情況下,find 是區分大小寫的。對於不區分大小寫的 find,將 -iname 測試替換為 -name 測試。

find downloads  -iname "*.gif"
downloads/.xvpics/Calendar05_enlarged.gif
downloads/lcmgcfexsmall.GIF
除檔名外,您還可以按型別搜尋檔案。例如,您可以使用以下命令查詢一個目錄中的所有子目錄:
find . -type d          

您可以使用以下命令查詢您的/usr 目錄中的所有符號連結:

find /usr -type l

這可能會列出 3,000 多個連結。以下的任何一個命令使用根許可權執行都將列出 /usr 目錄中的連結以及它所指向的檔案:

# find /usr/bin  -type l  -name "z*" -exec ls  -l {} /;
lrwxrwxrwx 1 root  root 8 Dec 12 23:17 /usr/bin/zsh -> /bin/zsh
lrwxrwxrwx 1 root  root 5 Dec 12 23:17 /usr/bin/zless -> zmore
lrwxrwxrwx 1 root  root 9 Dec 12 23:17 /usr/bin/zcat -> /bin/zcat
find /usr/bin -type  l  -name "z*" -ls

但是,第二個更短的命令將列出更多的檔案,以及目錄和 inode 資訊:在本文後面的部分中,我們將討論 -exec 和 -ls 操作的用法。

其他 find 可以找到的檔案型別包括:

• b — 塊(快取)特殊
• c — 字元(未快取)特殊
• p — 命名管道 (FIFO)
• s — 套接字

使用根作為 find 命令的起點會極大地降低系統的速度。如果您必須執行這樣一個命令,您可以在非高峰時段或晚上執行它。您可以使用以下語法將輸出重定向到一個檔案:

find  /   -print > masterfilelist.out

如果您錯誤地輸入一個 find 命令,生成大量不必要的輸出,只需按 CTRL-C 中斷該命令,這將停止最近執行的命令。

在具多個檔案系統的企業網路上,限制 find 查詢的檔案也是一個特別好用的方法。儘可能多地使用選項和測試以減少系統上的負載。用於此目的的兩個最有用的選項是 -xdev 和 -mount。它們通過阻止 find 下到其他檔案系統(如 MS-DOS、CD-ROM 或 AFS)上的目錄中縮短了搜尋範圍。這將搜尋限制為同一型別的檔案系統作為起始目錄。

如果執行 mount 命令,雙引導系統上的使用者可以使用這些選項。假設涉及 Windows 分割槽,您可以使用類似以下的命令安裝它:

mount -t vfat  /dev/sda1 /mnt/msdos

您使用的實際命令取決於您的系統設定。您可以通過執行 df 或執行以下命令驗證該分割槽已安裝:

find /mnt/msdos  -name "*.txt" 2> /dev/null

您應該看到 MS Windows 分割槽上列出了很多的檔案。現在,執行以下帶 -mount 或 -xdev 選項的命令:

find / -name  "*.txt" -mount 2> /dev/null

或者

find / -name  "*.txt" -xdev 2> /dev/null

還可以使用 -fstype 測試明確告知 find 在哪個檔案系統中查詢,如以下示例中所示:

find / -name  "*.txt" -fstype vfat 2> /dev/null

查詢時間

find 命令有幾個用於根據您系統的時間戳搜尋檔案的選項。這些時間戳包括

• mtime  檔案內容上次修改時間 
• atime — 檔案被讀取或訪問的時間
• ctime — 檔案狀態變化時間

mtime 和 atime 的含義都是很容易理解的,而 ctime 則需要更多的解釋。由於 inode 維護著每個檔案上的元資料,因此,如果與檔案有關的元資料發生變化,則 inode 資料也將變化。這可能是由一系列操作引起的,包括建立到檔案的符號連結、更改檔案許可權或移動了檔案等。由於在這些情況下,檔案內容不會被讀取或修改,因此 mtime 和 atime 不會改變,但 ctime 將發生變化。

這些時間選項都需要與一個值 n 結合使用,指定為 -n、n 或 +n

• -n 返回項小於 • +n 返回項大於 n• n 返回項正好與 n 相等

下面,我們來看幾個例子,以便於理解。以下命令將查詢在最近 1 小時內修改的所有檔案:

find . -mtime -1
./plsql/FORALLSample
./plsql/RegExpDNASample
/plsql/RegExpSample

用 1 取代 -1 運行同一命令將查詢恰好在 1 小時以前修改的所有檔案:

find . -mtime 1 

上述命令不會生成任何結果,因為它要求完全吻合。以下命令查詢 1 個多小時以前修改的所有檔案:

find . -mtime +1 
預設情況下,-mtime、-atime 和 -ctime 指的是最近 24 小時。但是,如果它們前面加上了開始時間選項,則 24 小時的週期將從當日的開始時間算起。您還可以使用 mmin、amin 和 cmin 查詢在不到 1 小時的時間內變化了的時間戳。

如果您在登入到您的帳戶後立即執行以下命令,您將找到在不到 1 分鐘以前讀取的所有檔案:

find . -amin -1
./.bashrc
/.bash_history
./.xauthj5FCx1

應該注意的是,使用 find 命令查詢檔案本身將更改該檔案的訪問時間作為其元資料的一部分。

您還可以使用 -newer、-anewer 和 –cnewer 選項查詢已修改或訪問過的檔案與特定的檔案比較。這類似於 -mtime、-atime 和 –ctime。
 
• -newer 指內容最近被修改的檔案
• -anewer 指最近被讀取過的檔案
• -cnewer 指狀態最近發生變化的檔案

要查詢您的主目錄中自上一個 tar 檔案以來以某種方式編輯過的所有檔案,使用以下命令:

find . -newer  backup.tar.gz

按大小查詢檔案

-size 選項查詢滿足指定的大小條件的檔案。要查詢所有大於 5MB 的使用者檔案,使用

find / -size  +5000000c 2> /dev/null
/var/log/lastlog
/var/log/cups/access_log.4
/var/spool/mail/bluher

結尾的“c”以位元組為單位報告我們的結果。預設情況下,find 以 512 位元組塊的數量報告大小。如果我們將“c”替換為“k”,我們還會看到以千位元組的數量報告的結果,如果使用“w”,則會看到以兩位元組字的數量報告的結果。

-size 選項經常用於搜尋所有零位元組檔案並將它們移至 /tmp/zerobyte 資料夾。以下命令恰好可以完成這一任務:

find test -type f  -size 0 -exec mv {} /tmp/zerobyte /;

-exec 操作允許 find 在它遇到的檔案上執行任何 shell 命令。在本文的後面部分,您將看到其用法的更多示例。大括號允許移動每個空檔案。

選項 -empty 還可用於查詢空檔案:

find test -empty        
test/foo
test/test

按許可權和所有者查詢

要監視您的系統安全離不開 find 命令。您可以使用符號或八進位制表示法查詢面向廣大使用者開放的檔案,如下所示:

find . -type f  -perm a=rwx -exec ls -l {} /; 

或者

find . -type f  -perm 777 -exec ls -l {} /;
-rwxrwxrwx 1 bluher  users 0 May 24 14:14 ./test.txt

在這一部分中,在上面和下面的命令中,我們使用了 -exec ls -l 操作,因此,您可以看到返回的檔案的實際許可權。以下命令將查詢可由“other”和組寫入的檔案:

find plsql -type f  -perm -ug=rw -exec ls -l {} /; 2>/dev/null

或者

find plsql -type f  -perm -220 -exec ls -l {} /; 2>/dev/null 
-rw-rw-rw- 1 bluher users 4303  Jun  7   2004 plsql/FORALLSample/doc/otn_new.css
-rw-rw-rw- 1 bluher users 10286 Jan  12  2005  plsql/FORALLSample/doc/readme.html
-rw-rw-rw- 1 bluher users 22647 Jan  12  2005  plsql/FORALLSample/src/config.sql
..
下一個命令將查詢由使用者、組或二者共同寫入的檔案:  
find plsql -type f  -perm /ug=rw -exec ls -l {} /; 2>/dev/null, or,
find plsql -type f  -perm /220 -exec ls -l {} /; 2>/dev/null 
-rw-r--r-- 1 bluher users 21473  May  3 16:02 plsql/regexpvalidate.zip
-rw-rw-rw- 1 bluher users 4303  Jun  7   2004 plsql/FORALLSample/doc/otn_new.css
-rw-rw-rw- 1 bluher users 10286 Jan  12  2005  plsql/FORALLSample/doc/readme.html
-rw-rw-rw- 1 bluher users 22647 Jan  12  2005  plsql/FORALLSample/src/config.sql

您可能會看到以下命令在 Web 和較早的手冊中引用過:

find . -perm +220  -exec ls -l {} /; 2> /dev/null 

+ 符號的作用與 / 符號相同,但是現在新版 GNU findutils 中不支援使用該符號。

要查詢您的系統上所有人都可以寫入的所有檔案,使用以下命令:

find / -wholename  '/proc' -prune  -o  -type f -perm -0002 -exec ls -l {} /;
-rw-rw-rw- 1 bluher users 4303  Jun  7   2004/home/bluher/plsql/FORALLSample/doc/otn_new.css
-rw-rw-rw- 1 bluher users 10286 Jan  12  2005  /home/bluher/plsql/FORALLSample/doc/readme.html
...

第 4 個許可權將在稍後進行討論,但最後一個欄位中的“2”是檔案許可權中的“other”欄位,也稱為寫入位。我們在許可權模式 0002 前面使用了破折號,以指明我們希望看到為 other 設定了寫許可權的檔案,無論其他許可權設定為什麼。

上述命令還引入了三個新概念。針對檔案模式“/proc”使用 -wholename 測試,如果該模式已找到,-prune 可防止 find 下到該目錄中。布林型別“-o”使 find 可以針對其他目錄處理該命令的其餘部分。由於每個表示式之間有一個假設的隱式 and 運算子 (-a),因此,如果左側的表示式計算結果為 false,and 之後的表示式將不進行計算;因此需要 -o 運算子。Find 還支援布林型別 -not、!,就像使用括號強行優先一樣。

系統管理員經常使用 find 通過使用者或組的名稱或 ID 搜尋特定使用者或組的常規檔案:

[root] $  find / -type f -user bluher -exec ls -ls {}  /;

下面是這樣一個命令的高度精簡的輸出示例:

4 -rw-r--r-- 1 bluher users 48  May  1 03:09  /home/bluher/public_html/.directory
4 -rw-r--r-- 1 bluher users 925  May  1 03:09 /home/bluher/.profile

您還可以使用 find 按組查詢檔案:

[root] $ find /  -type f -group users
find / -type d -gid  100

該命令將列出由 ID 為 100 的組擁有的目錄。要找到相應的 uid 或 gid,您可以針對 /etc/passwd 或 /etc/group 檔案執行 more 或 cat 命令。

除了查詢特定已知使用者和組的檔案外,您還會發現它對於查詢沒有這些資訊的檔案也很有用。下一個命令將識別未列在 /etc/passwd 或 /etc/group 檔案中的檔案:

find / -nouser -o  -nogroup

上述命令可能不會在您的系統上生成實際的結果。但是,它可用於識別或許在經常移動後沒有使用者或組的檔案。

好了,現在我們可以解決本部分開始時提到的格外重要的許可權了。

SGID 和 SUID 是特殊訪問許可權標誌,可以分配給基於 UNIX 的作業系統上的檔案和目錄。設定它們是為了允許訪問計算機系統的普通使用者使用臨時提升的許可權執行二進位制可執行檔案。

find /  /( -perm -2000 -o -perm -4000 /) -ls
167901   12 -rwsr-xr-x   1 root     root         9340 Jun 16  2006 /usr/bin/rsh
167334   12 -rwxr-sr-x   1 root     tty         10532 May  4  2007 /usr/bin/wall

在上述命令中,您可以看到轉義括號的使用。您還可以看到許可權的不同。第一個檔案設定了 SGID 許可權,第二個檔案設定了 SUID 許可權。上述命令中的最後的操作與帶 -exec ls -dils 操作的 find 效果類似。

控制 find

與 Linux 中的許多命令不同,find 不需要 -r 或 -R 選項即可下到子目錄中。它預設情況下就這樣操作。但是,有時您可能希望限制這一行為。因此,選項 -depth、-maxdepth 和 -mindepth 以及操作 -prune 就派上用場了。

我們已經看到了 -prune 是多麼有用,下面讓我們來看看 -depth、-maxdepth 和 -mindepth 選項。

-maxdepth 和 -mindepth 選項允許您指定您希望 find 搜尋深入到目錄樹的哪一級別。如果您希望 find 只在目錄的一個級別中查詢,您可以使用 maxdepth 選項。

通過執行以下命令在目錄樹的前三個級別中查詢日誌檔案,您可以看到 -maxdepth 的效果。使用該選項較之不使用該選項所生成的輸出要少得多。

find / -maxdepth 3  -name "*log"

您還可以讓 find 在至少下至目錄樹三個級別的目錄中查詢:

find / -mindepth 3  -name "*log"

-depth 選項確保先在一個目錄中進行查詢,然後才在其子目錄中進行查詢。以下命令提供了一個示例:

find -name "*test*" -depth
./test/test
./test
./localbin/test
./localbin/test_shell_var
./localbin/test.txt
./test2/test/test
./test2/test
./test2

find 世界

我們已經看過了 find 命令的一些更加有用以及有點難懂的功能,但是 find 還可以執行更多的任務。例如,有多個選項可以使 find 與較低的 UNIX 版本和其他作業系統相相容並允許您執行列印輸出到多個檔案等操作。閱讀本文後,您現在已經有了理解 find 參考指南的背景,我鼓勵您深入研究這一強大、有用的工具。