本節書摘來自華章出版社《建構高可用linux伺服器 第3版》一 書中的第3章,第3.4節,作者:餘洪春 ,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
這一節跟大家介紹一下linux強大的查找指令find。find的強大就在于它完美地支援了正規表達式。由于find具有強大的功能,是以它的選項也很多,其中大部分選項都值得我們花時間來了解一下。即使系統中含有網絡檔案系統(nfs),find指令在該檔案系統中也同樣有效,隻要具有相應的權限。在運作一個非常消耗資源的find指令時,很多人都傾向于把它放在背景執行,因為周遊一個大的檔案系統可能會花費很長的時間(這裡是指100gb以上的檔案系統)。
1.find指令的格式
find指令的一般形式如下:
find pathname -options [-print -exec -ok ...]
pathname:是find指令所查找的目錄路徑。例如用符号.來表示目前目錄,用/來表示系統根目錄。
-print:表示find指令将比對的檔案輸出到标準輸出中。
-exec:表示find指令對比對的檔案執行該參數所給出的shell指令。相應指令的形式為'command'{}\;,注意{}和符号\;之間的空格。
-ok:它的作用和-exec相同,隻不過是以一種更為安全的模式來執行該參數所給出的shell指令,即在執行每一個指令之前,都會給出提示,讓使用者來确定是否執行。
下面來看看find指令選項。
-name
按照檔案名查找檔案。
-perm
按照檔案權限來查找檔案。
-prune
使用這一選項可以使find指令不在目前指定的目錄中查找,如果同時使用-depth選項,那麼-prune将被find指令忽略。
-user
按照檔案屬主來查找檔案。
-group
按照檔案所屬的組來查找檔案。
-mtime -n+n
按照檔案的更改時間來查找檔案,-n表示從此刻算起,檔案的更改時間是在n天以内;+n表示檔案的更改時間是在n天以前。find指令還有-atime和-ctime選項,它們和-m time選項的時間規定類似。
-nogroup
查找無有效所屬組的檔案,即該檔案所屬的組在/etc/groups中不存在。
-nouser
查找無有效屬主的檔案,即該檔案的屬主在/etc/passwd中不存在。
-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指令,将這些檔案備份到錄音帶裝置中。
我們一般使用exec或ok來執行shell指令。
使用find時,隻要把想要的操作寫到一個檔案裡,就可以用exec來配合find查找,很友善。
在有些作業系統中隻允許-exec選項執行諸如ls或ls -l這樣的指令。大多數使用者使用這一選項是為了查找舊檔案并删除它們。建議在真正執行rm指令删除檔案之前,最好先用ls指令檢視一下,确認它們是所要删除的檔案。
exec選項後面跟随着所要執行的指令或腳本,然後是一對{}、一個空格和一個\符号,最後是一個分号。為了使用exec選項,必須要同時使用print選項。如果驗證一下find指令,你會發現該指令隻輸出從目前路徑起的相對路徑及檔案名。
例如:為了用ls -l指令列出所比對的檔案,可以把ls -l指令放在find指令的-exec選項中,如下所示:
find . -type f -exec ls -l {} \ ;
-rw------- 1 root root 1024 06-20 20:34 ./.rnd
-rw-r--r-- 1 root root 939 06-22 17:59 ./cat
-rw------- 1 root root 8022 06-22 19:47 ./.viminfo
-rw-r--r-- 1 root root 939 06-22 17:59 ./list.txt
-rw-r--r-- 1 root root 3972 06-15 13:30 ./install.log.syslog
-rwxr-xr-x 1 root root 448 06-21 11:45 ./rsync.sh
-rw-r--r-- 1 root root 100 2007-01-06 ./.cshrc
-rw-r--r-- 1 root root 36730 06-18 11:52 ./new_text_document.txt
-rw------- 1 root root 6 06-21 11:03 ./.mysql_history
-rw-r--r-- 1 root root 789 06-18 23:24 ./.ssh/known_hosts
-rw-r--r-- 1 root root 167 06-21 11:34 ./.vimrc
-rw-r--r-- 1 root root 191 2007-01-06 ./.bash_profile
-rw-r--r-- 1 root root 24 2007-01-06 ./.bash_logout
-rw-r--r-- 1 root root 309 06-19 23:23 ./.bashrc
-rw-r--r-- 1 root root 22772 06-15 13:30 ./install.log
-rw-r--r-- 1 root root 939 06-22 18:00 ./file
-rw------- 1 root root 1254 06-15 13:30 ./anaconda-ks.cfg
-rw-r--r-- 1 root root 129 2007-01-06 ./.tcshrc
-rw------- 1 root root 13844 06-22 10:07 ./.bash_history
在上面的例子中,find指令比對到了目前目錄下的所有普通檔案,并在-exec選項中使用ls -l指令将它們列出。
下面在/logs目錄中查找更改時間在5日以前的檔案并删除它們,如下所示:
find/logs -type f -mtime +5 -exec rm {} \ ;
注意 在shell中用任何方式删除檔案之前,應當先檢視相應的檔案,一定要小心使用諸如mv或rm的指令。可以使用安全模式-ok,它将在對每個比對到的檔案進行操作之前提示你。
在下面的例子中,find指令在目前目錄中查找所有檔案名以.log結尾、更改時間在5日以上的檔案,并删除它們,隻不過在删除之前先給出提示。指令如下所示:
find . -name "*.log" -mtime +5 -ok rm {} \ ;
按[y]鍵删除檔案,按[n]鍵不删除。
任何形式的指令都可以在-exec選項中使用。
在下面的例子中我們使用grep指令。先用find指令比對所有檔案名為“passwd*”的檔案,例如passwd、passwd.old、passwd.bak,然後執行grep指令看看在這些檔案中是否存在一個sam使用者。指令如下所示:
find /etc -name "passwd*" -exec grep "sam" {} \ ;
sam:x:501:501::/usr/sam:/bin/bash
2.find指令的執行個體說明
下面是find指令的執行個體說明。
1)查找目前使用者主目錄下的所有檔案,指令如下:
find ~ -print
2)讓目前目錄中的檔案屬主具有讀、寫權限,并且檔案所屬組的使用者和其他使用者具有讀權限的檔案,其實就是查找權限為644的檔案,指令如下:
find . -type f -perm 644 -exec ls -l {} \ ;
3)查找系統中所有檔案長度為0的普通檔案,并列出它們的完整路徑,指令如下:
find / -type f -size 0 -exec ls -l {} \ ;
4)查找/var/logs目錄中更改時間在7日以前的普通檔案,并在删除之前進行提示,指令如下所示:
find /var/logs -type f -mtime +7 -ok rm {} \ ;
5)查找目前目錄中所有屬于root組的檔案,指令如下所示:
find . -group root -exec ls -l { } \ ;
-rw-r--r-- 1 root root 789 06-18 23:24 known_hosts
6)find指令将删除目錄中通路時間在7日以内且含有數字字尾的admin.log檔案。
由于該指令隻檢查三位數字,是以相應檔案的字尾不要超過999。我們先建幾個admin.log*的檔案,然後再使用下面的指令删除:
find . -name "admin.log[0-9]" -atime -7 -ok rm {} \ ;
7)查找目前檔案系統中的所有目錄并排序,指令如下:
find . -type d | sort
/data
/data/htdocs
/data/logs
/data/mysql
/data/mysql/3306
/data/mysql/3306/binlog
/data/mysql/3306/data
/data/mysql/3306/data/mysql
/data/mysql/3306/data/performance_schema
/data/mysql/3306/data/test
/data/mysql/3306/relaylog
與shell下自帶的ls指令比較一下結果,你會發現find指令可以列出目前目錄下所有的目錄,我們可以根據需求來選擇到底采用哪種方法。下面看看shell下查找目錄的方法,如下所示:
ls –lf | grep /$
drwxrwxrwx 2 root root 4096 06-22 10:02 htdocs/
drwxr-xr-x 2 root root 4096 06-20 20:58 logs/
drwxr-xr-x 3 mysql mysql 4096 06-20 20:17 mysql/
8)查找系統中所有的rmt錄音帶裝置,指令如下:
find /dev/rmt -print
3.用xargs來配合find工作
在使用find指令的-exec選項處理比對到的檔案時,find指令将所有比對到的檔案一起傳遞給exec執行。但有些系統對傳遞給exec的指令長度是有限制的,這樣,在find指令運作幾分鐘之後,就會出現溢出錯誤。錯誤資訊通常是“參數列太長”或“參數列溢出”。這就是xargs指令的用處所在,特别是在與find指令一起使用時。
find指令把比對到的檔案傳遞給xargs指令,而xargs指令每次隻擷取一部分檔案而不是全部,不像-exec選項那樣。這樣它就可以先處理最先擷取的那一部分檔案,然後是下一批,并且如此繼續下去。
在有些系統中,使用-exec選項會為處理每一個比對到的檔案而發起一個相應的程序,并非将比對到的檔案全部作為參數一次執行。這樣,在有些情況下就會出現程序過多,系統性能下降的問題,因而效率不高。
而使用xargs指令則隻有一個程序。另外,在使用xargs指令時,究竟是一次擷取所有的參數,還是分批取得參數,包括每一次所擷取參數的數目,都會根據該指令的選項及系統核心中相應的可調參數來确定。
來看看xargs指令是如何同find指令一起使用的,同時給出一些例子。
1)下面的例子用來查找系統中的每一個普通檔案,然後使用xargs指令來測試它們分别屬于哪類檔案。