Linux Find 命令精通指南

轉自:http://www.oracle.com/technology/global/cn/pub/articles/calish-find.html

 

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 返回項正好與 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 參考指南的背景,我鼓勵您深入研究這一強大、有用的工具。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章