天天看點

find指令詳解(原創)

概述

有時可能需要在系統中查找具有某一特征的檔案(例如檔案權限、檔案屬主、檔案長度、檔案類型等等)。這樣做可能有很多原因。可能出于安全性的考慮,或是一般性的系統管理任務,或許隻是為了找出一個不知儲存在什麼地方的檔案。find一個非常有效的工具,它可以周遊目前目錄甚至于整個檔案系統來查找某些檔案或目錄。

由于find具有如此強大的功能,是以它的選項也很多,其中大部分選項都值得我們花時間來了解一下。即使系統中含有網絡檔案系統(nfs),find指令在該檔案系統中同樣有效,隻要你具有相應的權限。

在運作一個非常消耗資源的find指令時,很多人都傾向于把它放在背景執行,因為周遊一個大的檔案系統可能會花費很長的時間(這裡是指30g位元組以上的檔案系統).

find指令的使用

find pathname -options [-print -exec -ok]

find指令的一般格式為:

find  [-h] [-l] [-p]  [path...] [expression]

其中,'-h' '-l' '-p'三個選項主要是用來處理符号連接配接,'-h'表示隻跟随指令行中指定的符号連接配接,'-l'表示跟随所有的符号連接配接,'-p'是預設的選項,表示不跟随符号連接配接。

例如,在我的目前目錄下有一個符号連接配接e1000,現在我想查找檔案名中最後一個字母是數字的源檔案,那麼

$ find -h . -name "*[0-9].c" -print

./2234.c

像上面這樣寫隻能查找出目前目錄下符合要求的檔案,卻找不出e1000下的檔案。是以可以這麼寫:

$ find -h e1000 . -name "*[0-9].c" -print

或者使用 '-l'選項

$ find -l . -name "*[0-9].c" -print

格式中的[path...]部分表示以此目錄為根目錄進行搜尋。

格式中的[expression]是一個表達式。最基本的表達式分為三類:設定項(option)、測試項(test)、動作項(action),這三類又可以通過邏輯運算符(operator)組合在一起形成更大更複雜的表達式。設定項(如-depth,-maxdepth等)針對這次查找任務,而不是僅僅針對某一個檔案,設定項總是傳回true;測試項(test)則不同,它針對具體的一個檔案進行比對測試,如-name,-num,-user等,傳回true或者false;動作項(action)則是對某一個檔案進行某種動作(最常見的如-print),傳回true或者false。

正是[expression]部分的豐富,才使得find如此強大。此部分較複雜,後面慢慢說明。

find指令選項

find指令有很多選項或表達式,每一個選項前面跟随一個橫杠-。讓我們先來看一下該指令的主要選項,然後再給出一些例子。

-name   按照檔案名查找檔案。

-perm   按照檔案權限來查找檔案。

-prune   使用這一選項可以使find指令不在目前指定的目錄中查找,如果同時使用了-depth選項,那麼-prune選項将被find指令忽略。

-user   按照檔案屬主來查找檔案。

-group   按照檔案所屬的組來查找檔案。

-mtime -n or +n按照檔案的更改時間來查找檔案,-n表示檔案更改時間距現在n天以内,+n表示檔案更改時間距現在n天以前。find指令還有-atime和-ctime選項,但它們都和-mtime選項相似,是以我們在這裡隻介紹-mtime選項。

-nogroup   查找無有效所屬組的檔案,即該檔案所屬的組在/etc/groups中不存在。

-nouser   查找無有效屬主的檔案,即該檔案的屬主在/etc/password中不存在。

-newer file1 ! file2   查找更改時間比檔案file1新但比檔案file2舊的檔案。

-type   查找某一類型的檔案,諸如:

b - 塊裝置檔案。

d - 目錄。

c - 字元裝置檔案。

p - 管道檔案。

l - 符号連結檔案。

f - 普通檔案。

-size n[c]   查找檔案長度為n塊的檔案,帶有c時表示檔案長度以位元組計。

-depth   在查找檔案時,首先查找目前目錄中的檔案,然後再在其子目錄中查找。

-fstype   查找位于某一類型檔案系統中的檔案,這些檔案系統類型通常可以在配置檔案/etc/fstab中找到,該配置檔案中包含了本系統中有關檔案系統的資訊。

-mount   在查找檔案時不跨越檔案系統mount點。

-follow   如果find指令遇到符号連結檔案,就跟蹤至連結所指向的檔案。

-cpio   對比對的檔案使用cpio指令,将這些檔案備份到錄音帶裝置中。

使用name選項

檔案名選項是find指令最常用的選項,要麼單獨使用該選項,要麼和其他選項一起使用。可以使用某種檔案名模式來比對檔案,記住要用引号将檔案名模式引起來。

不管目前路徑是什麼,如果想要在自己的根目錄$home中查找檔案名符合*.txt的檔案,使用~作為pathname參數,波浪号~代表了你的$home目錄。

$ find ~ -name "*.txt" -print

想要在目前目錄及子目錄中查找所有的‘*.txt’檔案,可以用:

$ find . -name "*.txt" -print

想要的目前目錄及子目錄中查找檔案名以一個大寫字母開頭的檔案,可以用:

$ find . -name "[a-z]*" -print

想要在/etc目錄中查找檔案名以h o s t開頭的檔案,可以用:

$ find /etc -name "host*" -print

如果想在目前目錄查找檔案名以兩個小寫字母開頭,跟着是兩個數字,最後是* . t x t的文

件,下面的指令就能夠傳回名為ax37.txt的檔案:

$ find . -name "[a-z][a-z][0--9][0--9].txt" -print

使用perm選項

如果希望按照檔案權限模式來查找檔案的話,可以采用-perm選項。你可能需要找到所有使用者都具有執行權限的檔案,或是希望檢視某個使用者目錄下的檔案權限類型。在使用這一選項的時候,最好使用八進制的權限表示法。為了在目前目錄下查找檔案權限位為7 5 5的檔案,即檔案屬主可以讀、寫、執行,其他使用者可以讀、執行的檔案,可以用:

$ find . -perm 755 -print邏輯運算符

find中的邏輯運算符主要有以下幾個,按照優先級從高到低的順序如下:

 ( expr )

括号優先級最高,首先對括号内的求值

 ! expr

對expr表達式的值取反

 -not expr

同上,但是posix不支援

 expr1 expr2

不加任何運算符,相當于兩個之間加and,即與運算,兩個表達式值都為true整個才傳回true。先對expr1表達式求值,若為false,則不對expr2求值。

 expr1 -a expr2

同上

 expr1 -and expr2

 expr1 -o expr2

表示對expr1和expr2兩個表達式的值求或,左右兩個值隻要有一個為ture,整個表達式就是true。先對expr1表達式求值,若為ture,則不對expr2求值。

 expr1 -or expr2

 expr1 , expr2

逗号表達式。expr1和expr2都會求值,但是隻傳回expr2的值,expr1的值會被丢棄

使用prune選項

find指令遞歸周遊所指定的目錄樹,針對每個檔案依次執行find指令中的表達式,表達式首先根據邏輯運算符進行結合,然後依次從左至右對表達式求值。以下面代碼為例,進行說明

find pathp1 opt1 test1 act1 ( test2 or test3 ) act2

1、根據opt1設定項進行find指令的整體設定,若沒有-depth設定項,依次進行下面的步驟

2、令檔案變量file = pathp1

3、對file檔案進行test1測試,若執行結果為false,轉(8)

4、對file檔案進行act1動作,若執行結果為false,轉(8)

5、對file檔案進行test2測試,若執行結果為true,轉(7)

6、對file檔案進行test3測試,若執行結果為false,轉(8)

7、對file檔案進行act2動作

8、若file檔案是一個目錄,并且沒有被執行過-prune動作,則進入此目錄

9、目前目錄下是否還有檔案,若有依次取一個檔案,令file指向此檔案,轉(3);

10、判斷目前目錄是否是pathp1,若是則程式退出;若不是,則傳回上一層目錄,轉(9)

了解了上面的流程,那麼不難了解下面的代碼為什麼隻輸出一個'.'

$ find . -prune

.

再有,目前目錄下大于4090位元組的檔案有兩個,而大于4096位元組的檔案隻有一個,如下:

$ find . -size +4090c -print

./a_book_of_c.chm

$ find . -size +4096c -print

那麼,将上面兩個-print都替換為-prune,這兩條指令分别輸出什麼?

$ find . -size +4090c -prune

$ find . -size +4096c -prune

-prune經常和-path或-wholename一起使用,以避開某個目錄,常見的形式是:

$ find path (-path <don't want this path #1> -o -path <don't want this path #2>) -prune -o -path <global expression for what i do want>

$ find . -size +0c -wholename "*e*[0-9]*" -o ! /( -name "." -o -name "*phone" /) -prune  -name "*.c" -user xixi -o -name "*phone"

如果在查找檔案時希望忽略某個目錄,因為你知道那個目錄中沒有你所要查找的檔案,那麼可以使用-prune選項來指出需要忽略的目錄。在使用-prune選項時要當心,因為如果你同時使用了-depth選項,那麼-prune選項就會被find指令忽略。

如果希望在/apps目錄下查找檔案,但不希望在/apps/bin目錄下查找,可以用:

$ find /apps -name "/apps/bin" -prune -o -print

使用user和nouser選項

如果希望按照檔案屬主查找檔案,可以給出相應的使用者名。例如,在$home目錄中查找檔案屬主為dave的檔案,可以用:

$ find ~ -user dave -print

在/etc目錄下查找檔案屬主為uucp的檔案:

$ find /etc -user uucp -print

為了查找屬主帳戶已經被删除的檔案,可以使用-nouser選項。這樣就能夠找到那些屬主在/etc/password檔案中沒有有效帳戶的檔案。在使用-nouser選項時,不必給出使用者名;find指令

能夠為你完成相應的工作。例如,希望在/home目錄下查找所有的這類檔案,可以用:

$ find /home -nouser -print

使用group和nogroup選項

就像user和nouser選項一樣,針對檔案所屬于的使用者組,find指令也具有同樣的選項,為了在/apps目錄下查找屬于accts使用者組的檔案,可以用:

$ find /apps -group accts -print

要查找沒有有效所屬使用者組的所有檔案,可以使用nogroup選項。下面的find指令從檔案系統的根目錄處查找這樣的檔案

$ fine / -nogroup -print

按照更改時間查找檔案

如果希望按照更改時間來查找檔案,可以使用mtime選項。如果系統突然沒有可用空間了,很有可能某一個檔案的長度在此期間增長迅速,這時就可以用mtime選項來查找這樣的檔案。用減号-來限定更改時間在距今n日以内的檔案,而用加号+來限定更改時間在距今n日以前的檔案。

希望在系統根目錄下查找更改時間在5日以内的檔案,可以用:

$ find / -mtime -5 -print

為了在/var/adm目錄下查找更改時間在3日以前的檔案,可以用:

$ find /var/adm -mtime +3 -print

使用newer選項

如果希望查找更改時間比某個檔案新但比另一個檔案舊的所有檔案,可以使用-newer選項。它的一般形式為:

newest_file_name ! oldest_file_name

其中,!是邏輯非符号。這裡有兩個檔案,它們的更改時間大約相差兩天。

下面給出的find指令能夠查找更改時間比檔案age.awk新但比檔案belts.awk舊的檔案:

$find . -newer age.awk ! -newer belts.awk -exec ls -l {} \;

如果想使用find指令的這一選項來查找更改時間在兩個小時以内的檔案,除非有一個現成的檔案其更改時間恰好在兩個小時以前,否則就沒有可用來比較更改時間的檔案。為了解決這一問題,可以首先建立一個檔案并将其日期和時間戳設定為所需要的時間。這可以用touch指令來實作。

假設現在的時間是2 3 : 4 0,希望查找更改時間在兩個小時以内的檔案,可以首先建立這樣

一個檔案:

$touch -t 05042140 dstamp

一個符合要求的檔案已經被建立;這裡我們假設今天是五月四日,而該檔案的更改時間是21:40,比現在剛好早兩個小時。

現在我們就可以使用find指令的-newer選項在目前目錄下查找所有更改時間在兩個小時以内的檔案:

$ find . -newer dstamp -print

使用type選項

unix或linux系統中有若幹種不同的檔案類型,這部分内容我們在前面的章節已經做了

如果要在/etc目錄下查找所有的目錄,可以用:

$ find /etc -type d -print

為了在目前目錄下查找除目錄以外的所有類型的檔案,可以用:

$ find . ! -type d -print

為了在/etc目錄下查找所有的符号連結檔案,可以用:

$ find /etc -type l -print

使用size選項

可以按照檔案長度來查找檔案,這裡所指的檔案長度既可以用塊(block)來計量,也可以用位元組來計量。以位元組計量檔案長度的表達形式為n c;以塊計量檔案長度隻用數字表示即可。就我個人而言,我總是使用以位元組計的方式,在按照檔案長度查找檔案時,大多數人都喜歡使用這種以位元組表示的檔案長度,而不用塊的數目來表示,除非是在檢視檔案系統的大小,因為這時使用塊來計量更容易轉換。

為了在目前目錄下查找檔案長度大于1 m位元組的檔案,可以用:

$ find . -size +1000000c -print

為了在/home/apache目錄下查找檔案長度恰好為1 0 0位元組的檔案,可以用:

$ find /home/apache -size 100c -print

為了在目前目錄下查找長度超過1 0塊的檔案(一塊等于5 1 2位元組),可以用:

$ find . -size +10 -print

使用depth選項

在使用find指令時,可能希望先比對所有的檔案,再在子目錄中查找。使用depth選項就可以使find指令這樣做。這樣做的一個原因就是,當在使用find指令向錄音帶上備份檔案系統時,希望首先備份所有的檔案,其次再備份子目錄中的檔案。

在下面的例子中,find指令從檔案系統的根目錄開始,查找一個名為con.file的檔案。

它将首先比對所有的檔案然後再進入子目錄中查找。

$ find / -name "con.file" -depth -print

使用mount選項

在目前的檔案系統中查找檔案(不進入其他檔案系統),可以使用f i n d指令的m o u n t選項。

在下面的例子中,我們從目前目錄開始查找位于本檔案系統中檔案名以x c結尾的檔案:

$ find . -name "*.xc" -mount -print

使用cpio選項

cpio指令可以用來向錄音帶裝置備份檔案或從中恢複檔案。可以使用find指令在整個檔案系統中(更多的情況下是在部分檔案系統中)查找檔案,然後用cpio指令将其備份到錄音帶上。如果希望使用cpio指令備份/etc/、/home/和/apps目錄中的檔案,可以使用下面所給出的指令,不過要記住你是在檔案系統的根目錄下:

$cd /

$find etc home apps -depth -print | cpio -ivcdc65536 -o /dev/rmt0

(在上面的例子中,第一行末尾的\告訴shell指令還未結束,忽略\後面的回車。)

在上面的例子中,應當注意到路徑中缺少/,這叫作相對路徑。之是以使用相對路徑,是因為在從錄音帶中恢複這些檔案的時候,可以選擇恢複檔案的路徑。例如,可以将這些檔案先恢複到另外一個目錄中,對它們進行某些操作後,再恢複到原始目錄中。如果在備份時使用了絕對路徑,例如/etc,那麼在恢複時,就隻能恢複到/ etc目錄中去,别無其他選擇。在上面

的例子中,我告訴find指令首先進入/etc目錄,然後是/home和/apps目錄,先比對這些目錄下的檔案,然後再比對其子目錄中的檔案,所有這些結果将通過管道傳遞給cpio指令進行備份。順便說一下,在上面的例子中cpio指令使用了c65536選項,我本可以使用b選項,不過這

樣每塊的大小隻有5 1 2位元組,而使用了c65536選項後,塊的大小變成了64k位元組(65536 /1024)。

使用exec或ok來執行shell指令

當比對到一些檔案以後,可能希望對其進行某些操作,這時就可以使用-exec選項。

-exec選項讓find指令對比對的檔案執行該參數所給出的shell指令。相應指令的形式為' command' {} \;,注意{ }和\;之間的空格。-ok和-exec的作用相同,隻不過以一種更為安全的模式來執行該參數所給出的shell指令,在執行每一個指令之前,都會給出提示,讓使用者來确定是否執行。一旦find指令比對到了相應的檔案,就可以用-exec項中的指令對其進行操作(在有些作業系統中隻允許-exec選項執行諸如l s或ls -l這樣的指令)。大多數使用者使用這一選項是為了查找舊檔案并删除它們。這裡我強烈地建議你在真正執行rm指令删除檔案之前,最好先用ls指令看一下,确認它們是所要删除的檔案。

為了使用exec選項,必須要同時使用print選項。如果驗證一下find指令,會發現該指令隻輸出從目前路徑起的相對路徑及檔案名。

為了用ls -l指令列出所比對到的檔案,可以把ls -l指令放在find指令的-exec選項中,例如:

$find . -type f -exec ls -l {} \;

上面的例子中,find指令比對到了目前目錄下的所有普通檔案,并在-exec選項中使用ls -l指令将它們列出。

為了在/logs目錄中查找更改時間在5日以前的檔案并删除它們,可以用:

$ find logs -type f -mtime +5 -exec rm {} \;

記住,在shell中用任何方式删除檔案之前,應當先檢視相應的檔案,一定要小心!當使用諸如mv或rm指令時,可以使用-exec選項的安全模式。它将在對每個比對到的檔案進行操作之前提示你。在下面的例子中,find指令在目前目錄中查找所有檔案名以. log結尾、更改時間在5日以上的檔案,并删除它們,隻不過在删除之前先給出提示。

按y鍵删除檔案,按n鍵不删除。

任何形式的指令都可以在-exec選項中使用。在下面的例子中我們使用grep指令。find指令首先比對所有檔案名為“password*”的檔案,例如password,password.old,password.bak,然後執行grep指令看看在這些檔案中是否存在一個rounder使用者。

$find /etc -name "password*"  -exec grep "rounder" {} \;

使用-regex選項

-regex同樣屬于測試項。使用-regex時有一點要注意:-regex不是比對檔案名,而是比對完整的檔案名(包括路徑)。例如,目前目錄下有一個檔案"abar9",如果你用"ab.*9"來比對,将查找不到任何結果,正确的方法是使用".*ab.*9"或者".*/ab.*9"來比對。針對上面的那個查找c代碼的問題,可以這麼寫:

$ find . -regex ".*/[0-9]*/.c" -print

使用wholename與path選項

這裡-wholename和-path和上面提到的全路徑有一定關聯。

-wholename和-path都屬于測試項(test),而且功能也一樣。-path從字面上看給人一種錯覺,好像隻比對路徑名(或者目錄名),其實它也可以比對檔案名,是以-wholename這個名字更貼切一些。看看這個例子,目前目錄下有一個phone目錄,phone目錄裡有一個檔案名稱是puk.txt,使用-path:

$ find . -path '*phone/pu*'

./phone/puk.txt

另外要提一點:使用-path的一般格式是:find [path ...] -path pattern ...

它的意思是:在[path ...]部分指明的路徑上,使用pattern比對所有檔案的完整檔案名;而不是說在類似的pattern目錄下查找檔案。

輸出格式

如果你不想查找到你想要的檔案事單調的輸出檔案名,你可以使用-printf動作項輸出你想要的格式,下面舉幾個-printf動作的參數:

%p    輸出檔案名,包括路徑名

%f     輸出檔案名,不包括路徑名

%m    以8進制方式輸出檔案的權限

%g    輸出檔案所屬的組

%h    輸出檔案所在的目錄名

%u    輸出檔案的屬主名

...

例如:

$ find . -user xixi -printf "%m %p //n"

644 ./phone1/hello.c 

644 ./0dfe.c 

find和xargs

在使用find指令的-exec選項處理比對到的檔案時,find指令将所有比對到的檔案一起傳遞給exec執行。不幸的是,有些系統對能夠傳遞給exec的指令長度有限制,這樣在find指令運作幾分鐘之後,就會出現溢出錯誤。錯誤資訊通常是“參數列太長”或“參數列溢出”。這就是

xargs指令的用處所在,特别是與find指令一起使用。find指令把比對到的檔案傳遞給xargs指令,而x a rg s指令每次隻擷取一部分檔案而不是全部,不像-exec選項那樣。這樣它可以先處理最先擷取的一部分檔案,然後是下一批,并如此繼續下去。在有些系統中,使用-exec選項會為處理每一個比對到的檔案而發起一個相應的程序,并非将比對到的檔案全部作為參數一次執行;這樣在有些情況下就會出現程序過多,系統性能下降的問題,因而效率不高;而使用xargs指令則隻有一個程序。另外,在使用xargs指令時,究竟是一次擷取所有的參數,還是分批取得參數,以及每一次擷取參數的數目都會根據該指令的選項及系統核心中相應的可調參

數來确定。

下面的例子查找系統中的每一個普通檔案,然後使用xargs指令來測試它們分别屬于哪類檔案:下面的例子在整個系統中查找記憶體資訊轉儲檔案 (core dump),然後把結果儲存到/tmp/core.log 檔案中:

$ find . -name "core" -print | xargs echo "" >/tmp/core.log

下面的例子在/apps/audit目錄下查找所有使用者具有讀、寫和執行權限的檔案,并收回相應的寫權限:

$ find /apps/audit -perm -7 -print | xargs chmod o-w

在下面的例子中,我們用g r e p指令在所有的普通檔案中搜尋device這個詞:

$ find / -type f -print | xargs grep "device"

在下面的例子中,我們用grep指令在目前目錄下的所有普通檔案中搜尋dbo這個詞:

$ find . -name \* -type f -print | xargs grep "dbo"

注意,在上面的例子中,\用來取消f i n d指令中的*在shell中的特殊含義。

參考至:《linux與unix shell程式設計指南》

                    http://blog.csdn.net/jakee304/article/details/1792830

                    http://tech.ddvip.com/2008-09/122069016161378.html

本文原創,轉載請注明出處、作者

如有錯誤,歡迎指正

郵箱:[email protected]

作者:czmmiao  文章出處:http://czmmiao.iteye.com/blog/1881788