find命令是我們日常工作中比較常用的Linux命令。全面的掌握這個命令可以使很多操作達到事半功倍的效果。如果對find命令有以下這些疑惑,本文都能幫你解決,快來學習吧!
1、find命令的格式是什麼?
2、引數中出現+或-號是什麼意思?比如find / -mtime +7與find / -mtime -7什麼區別?
3、find /etc/ -name “passwd” -exec echo {} ;和find /etc/ -name “passwd” -exec echo {} +有啥區別?
4、-exec引數為什麼要以“;”結尾,而不是隻寫“;”?
命令基礎
find命令大家都比較熟悉,反倒想講的有特色比較困難。那乾脆我們怎麼平淡怎麼來好了。我們一般用的find命令格式很簡單,一般分成三個部分:
find /etc -name "passwd"
格式如上,第一段find命令。第二段,要搜尋的路徑。這一段目錄可以寫多個,如:
find /etc /var /usr -name "passwd"
第三段,表示式。我們例子中用的是-name “passwd”這個表示式,指定條件為找到檔名是passwd的檔案。對於find命令,最需要學習的是表示式這一段。表示式決定了我們要找的檔案是什麼屬性的檔案,還可以指定一些“動作”,比如將匹配某種條件的檔案刪除。所以,find命令的核心就是表示式(EXPRESSION)的指定方法。
find命令中的表示式有四種類型,分別是:
1、Tests:就是我們最常用的指定查詢檔案的條件。
2、Actions:對找到的檔案可以做的操作。
3、Global options:全域性屬性用來限制一些查詢的條件,比如常見的目錄層次深度的限制。
4、Positional options:位置屬性用來指定一些查詢的位置條件。
這其中最重要的就是Tests和Actions,他們是find命令的核心。另外還有可以將多個表示式連線起來的操作符,他們可以表達多個表示式之間的邏輯關係和運算優先順序,叫做Operators。
下面我們就來分類看一下這些個分類的功能。
TESTS
find命令是通過檔案屬性查詢檔案的。所以,find表示式的tests都是檔案的屬性條件,比如檔案的各種時間,檔案許可權等。很多引數中會出現指定一個數字n,一般會出現三種寫法:
+n:表示大於n。
-n:表示小於n。
n:表示等於n。
根據時間查詢
比較常用數字方式來指定的引數是針對時間的查詢,比如-mtime n:查詢檔案修改時間,單位是天,就是n*24小時。舉個例子說:
[root@zorrozou-pc0 zorro]# find / -mtime 7 -ls
我們為了方便看到結果,在這個命令中使用了-ls引數,具體細節後面會詳細解釋。再此我們只需要知道這個引數可以將符合條件的檔案的相關屬性顯示出來即可。那麼我們就可以通過這個命令看到查詢到的檔案的修改時間了。
[root@zorrozou-pc0 zorro]# find / -mtime 7 -ls|head
524295 4 drwxr-xr-x 12 root root 4096 6月 8 13:43 /root/ig
524423 4 drwxr-xr-x 2 root root 4096 6月 8 13:43 /root/ig/yelp
524299 4 drwxr-xr-x 2 root root 4096 6月 8 13:23 /root/ig/dconf
524427 4 -rw-r--r-- 1 root root 3040 6月 8 13:23 /root/ig/dconf/user
...
我們會發現,時間都集中在6月8號,而今天是:
[root@zorrozou-pc0 zorro]# date
2016年 06月 15日 星期三 14:30:09 CST
實際上,當我們在mtime後面指定的是7的時候,實際上是找到了距離現在7個24小時之前修改過的檔案。如果我們在考究一下細節的話,可以使用這個命令再將找到的檔案用時間排下順序:
[root@zorrozou-pc0 zorro]# find / -mtime 7 -exec ls -tld {} +
此命令用到了exec引數,後面會詳細說明。我們會發現,找到的檔案實際上是集中在6月7日的14:30到6月8日的14:30這個範圍內的。就是說,實際上,指定7天的意思是說,找到檔案修改時間範圍屬於距離當前時間7個24小時到8個24小時之間的檔案,這是不加任何+-符號的7的含義。如果是-mtime -7呢?
[root@zorrozou-pc0 zorro]# find / -mtime -7 -exec ls -tld {} +
你會發現找到的檔案是從現在開始到7個24小時範圍內的檔案。但是不包括7個24小時到8個24小時的時間範圍。那麼-mtime +7也應該好理解了。這就是find指定時間的含義。類似的引數還有:
-ctime:以天為單位通過change time查詢檔案。
-atime:以天為單位通過access time查詢檔案。
-mmin:以分鐘為單位通過modify time查詢檔案。
-amin:以分鐘為單位通過access time查詢檔案。
-cmin:以分鐘單位通過change time查詢檔案。
這些引數都是指定一個時間數字n,數字的意義跟mtime完全一樣,只是時間的單位和查詢的時間不一樣。
除了指定時間以外,find還可以通過對比某一個檔案的相關時間找到符合條件的檔案,比如-anewer file。
[root@zorrozou-pc0 zorro]# find /etc -anewer /etc/passwd
這樣可以在/etc/目錄下找到檔案的access time比/etc/passwd的access time更新的所有檔案。類似的引數還有:
-cnewer:比較檔案的change time。
-newer:比較檔案的modify time。
-newer還有一種特殊用法,可以用來做各種時間之間的比較。比如,我想找到檔案修改時間比/etc/passwd檔案的change time更新的檔案:
[root@zorrozou-pc0 zorro]# find /etc/ -newermc /etc/passwd
這個用法的原型是:find /etc/ -newerXY file。其中Y表示的是跟後面file的什麼時間比較,而X表示使用查詢檔案什麼時間進行比較。-newermc就是拿檔案的modify time時間跟file的change time進行比較。X和Y可以使用的字母為:
a:檔案access time。
c:檔案change time。
m:檔案modify time。
在某些支援記錄檔案的建立時間的檔案系統上,可以使用B來表示檔案建立時間。ext系列檔案系統並不支援記錄這個時間。
根據使用者查詢
-uid n:檔案的所屬使用者uid為n。
-user name:檔案的所屬使用者為name。
-gid n:檔案的所屬組gid為n。
-group name:所屬組為name的檔案。
-nogroup:沒有所屬組的檔案。
-nouser:沒有所屬使用者的檔案。
根據許可權查詢
-executable:檔案可執行。
-readable:檔案可讀。
-writable:檔案可寫。
-perm mode:查詢許可權為mode的檔案,mode的寫法可以是數字,也可以是ugo=rwx的方式如:
[root@zorrozou-pc0 zorro]# find /etc/ -perm 644 -ls
這個寫法跟:
[root@zorrozou-pc0 zorro]# find /etc/ -perm u=rw,g=r,o=r -ls
是等效的。
另外要注意,mode指定的是完全符合這個許可權的檔案,如:
[root@zorrozou-pc0 zorro]# find /etc/ -perm u=rw,g=r -ls
263562 4 -rw-r----- 1 root brlapi 33 11月 13 2015 /etc/
沒描述的許可權就相當於指定了沒有這個許可權。
mode還可以使用/或-作為字首進行描述。如果指定了-mode,就表示沒指定的許可權是忽略的,就是說,許可權中只要包涵相關許可權即可。如:
[root@zorrozou-pc0 zorro]# find /etc/ -perm 600 -ls
這是找到所有隻有rw———-許可權的檔案,而-600就表示只要是包括了rw的其他位任意的檔案。mode加/字首表示的是,指定的許可權只要某一位複合條件就可以,其他位跟-一樣忽略,就是說-perm /600還可以找到r————或者-w———-這樣許可權的檔案。老版本的/字首是用+表示的,新版本的find意境不支援mode前加+字首了。
根據路徑查詢
-name pattern:檔名為pattern指定字串的檔案。注意如果pattern中包括*等特殊符號的時候,需要加””。
-iname:name的忽略大小寫版本。
-lname pattern:查詢符號連線檔名為pattern的檔案。
-ilname:lname的忽略大小寫版本。
-path pattern:根據完整路徑查詢檔名為pattern的檔案,如:
[root@zorrozou-pc0 zorro]# find /etc -path "/e*d"| head
/etc/machine-id
/etc/profile.d
/etc/vnc/
/etc/vnc/config.d
/etc/vnc/updateid
/etc/ted
-ipath:path的忽略大小寫版本。
-regex pattern:用正則表示式匹配檔名。
-iregex:regex的忽略大小寫版本。
其他狀態查詢
-empty:檔案為空而且是一個普通檔案或者目錄。
-size n[cwbkMG]:指定檔案長度查詢檔案。單位選擇位:
c:位元組單位。
b:塊為單位,塊大小為512位元組,這個是預設單位。
w:以words為單位,words表示兩個位元組。
k:以1024位元組為單位。
M:以1048576位元組為單位。
G:以1073741824位元組溫單位。
n的數字指定也可以使用+-號作為字首。意義跟時間類似,表示找到小於(-)指定長度的檔案或者大於(+)指定長度的檔案。
-inum:根據檔案的inode編號查詢。
-links n:根據檔案連線數查詢。
-samefile name:找到跟name指定的檔案完全一樣的檔案,就是說兩個檔案是硬連線關係。
-type c:以檔案型別查詢檔案:
c可以選擇的型別為:
b:塊裝置
c:字元裝置
d:目錄
p:命名管道
f:普通檔案
l:符號連線
s:socket
ACTIONS
表示式中的actions型別引數主要是用來對找到的檔案進行操作的引數。在上面的例子中,我們已經看到可以使用-ls引數對找到的檔案進行長格式顯示,這就是一個actions型別的引數。類似的引數還有。
-fls file:跟-ls功能一樣,區別是將資訊寫入file指定的檔案,而不是顯示在螢幕上。
-print:將找到的檔案顯示在螢幕上,實際上預設find命令就會將檔案打印出來顯示。
-print0:-print引數會將每個檔案用換行分割,而這個引數適用null分割。有時候在指令碼程式設計時可能會用上。
-fprint file:-print引數的寫入檔案版本。將內容寫到檔案中,而不是顯示在螢幕上。
-fprint0 file:-print0的寫入檔案版本。
-delete:可以將找到的檔案直接刪除。
-printf:格式化輸出方式列印。如:
[root@zorrozou-pc0 zorro]# find /etc/ -name "pass*" -printf "%p "
/etc/default/passwd /etc/pam.d/passwd /etc/passwd- /etc/passwd
顯示檔名,並以空格分隔。%p代表檔名。其他資訊可以參見man find。
-prune:如果複合條件的是一個目錄,則不進入目錄進行查詢。例子:
[root@zorrozou-pc0 zorro]# mkdir /etc/passs
[root@zorrozou-pc0 zorro]# touch /etc/passs/passwd
[root@zorrozou-pc0 zorro]# find /etc/ -name "pass*" -prune
/etc/passs
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd-
/etc/passwd
[root@zorrozou-pc0 zorro]# find /etc/ -name "pass*"
/etc/passs
/etc/passs/passwd
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd-
/etc/passwd
我們先建立了一個/etc/passs的目錄,然後在這個目錄下建立了一個叫passwd的檔案。之後先用帶-prune的find看到,能顯示出passs目錄,但是目錄中的passwd檔案並沒有顯示,說明這個引數讓find命令沒有進入這個目錄查詢。而後一個不帶-prune引數的find顯示出了passs目錄下的passwd。
-quit:找到符合條件的檔案後立即退出。
find中執行命令
-exec
find命令的exec是一個非常好用的引數,當然其可能造成的破壞也可能非常大。在學習它之前,我先要提醒大家,使用之前千萬要確定自己在做什麼。
這個引數的常見格式是:
-exec command ;
注意後面的分號。它是用來給find做標記用的。find在解析命令的時候,要區分給定的引數是要傳給自己的還是要傳給command命令的。所以find以分號作為要執行命令所有引數的結束標記。命令返回值為0則返回true。在exec引數指定的執行命令中,可以使用{}符號表示當前find找到的檔名。比如:
[root@zorrozou-pc0 find]# find /etc/ -name "passwd" -exec echo {} ;
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd
上面的命令表示,找到/etc/目錄下檔名為passwd的檔案,並echo其檔名。注意再使用分號的時候前面要加轉移字元,因為分號也是bash的特殊字元,所以bash會先解釋它。前面加上就可以讓bash直接將其船體給find命令,這個分號由find解釋,而不是bash。其實這個exec用的比較廢話,畢竟find本身就會找到相關條件的檔案並顯示其檔名。但是試想如果我們將echo換成rm或者cp,是不是就有意義的多?比如:
[root@zorrozou-pc0 find]# find /etc/ -name "passwd" -exec rm {} ;
請不要執行這個命令!!
或者:
[root@zorrozou-pc0 find]# find /etc/ -name "passwd" -exec cp {} {} ;
這個命令可以將符合條件的檔案都加個字尾備份一份。於是我們可以執行刪除了:
[root@zorrozou-pc0 find]# find /etc/ -name ""
/etc/default/
/etc/pam.d/
/etc/
[root@zorrozou-pc0 find]# find /etc/ -name "" -exec rm {} ;
[root@zorrozou-pc0 find]# find /etc/ -name ""
當然,刪除前還是要確認清楚你要刪的檔案一定是對的`。
-execdir
execdir和exec有一些差別,主要是在執行指定的命令時,那個相關命令是在那個工作目錄下執行的差別。exec是在find所指定的起始目錄,而execdir是檔案所在目錄。對比一下就明白了:
[root@zorrozou-pc0 find]# find /etc/ -name "passwd" -exec echo {} ;
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd
[root@zorrozou-pc0 find]# find /etc/ -name "passwd" -execdir echo {} ;
./passwd
./passwd
./passwd
一個命令打印出來的路徑都是/etc/開頭,另一個顯示的都是當前目錄下的某某檔案。
execdir的方式要比exec安全一些,因為這種執行方式避免了在解析檔名時所產生的競爭條件。
出了上述兩種比較典型的執行命令的方法以外,find還對這兩個引數提供了另一種形式的命令執行格式:
-exec command {} +
-execdir command {} +
我們還是先用例子來看一下這個格式和以分號結束的方式的差別:
[root@zorrozou-pc0 find]# find /etc/ -name "passwd" -exec echo {} ;
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd
[root@zorrozou-pc0 find]# find /etc/ -name "passwd" -exec echo {} +
/etc/default/passwd /etc/pam.d/passwd /etc/passwd
光這樣看可能還不是很明顯,我們可以這樣在描述一遍他們的執行過程:
echo /etc/default/passwd
echo /etc/pam.d/passwd
echo /etc/passwd
和
echo /etc/default/passwd /etc/pam.d/passwd /etc/passwd
其實就是說,對於command {} ;格式來說,每找到一個檔案就執行一遍相關命令,而command {} +格式的意思是說,先執行find,找到所有符合條件的檔案之後,將每個檔案作為命令的一個引數傳給命令執行,exec指定的命令實際上只被執行了一次。這樣用的限制也是不言而喻的:{}只能出現一次。
[root@zorrozou-pc0 find]# find /etc -mtime -7 -type f -exec cp -t /tmp/back/ {} +
上面這個命令將符合條件的檔案全部cp到了/tmp/back目錄中,當然如果檔案有重名的情況下,會被覆蓋掉。從這個命令中我們學習一下{} +格式的使用注意事項,它不能寫成:
find /etc -mtime -7 -type f -exec cp {} /tmp/back/ +
所以只能使用-t引數改變cp命令的引數順序來指定相關的動作。
無論如何,直接使用exec和execdir是很危險的,因為他們會直接對找到的檔案呼叫相關命令,並且沒有任何確認。所以我們不得不在進行相關操作前再三確認,以防止誤操作。當然,find命令也給了更安全的exec引數,它們就是:
-ok
-okdir
它們的作用跟exec和execdir一樣,區別只是在做任何操作之前,會讓使用者確認是不是ok?如:
[root@zorrozou-pc0 find]# find /etc -mtime -7 -type f -ok cp -t /tmp/back/ {} ;
< cp ... /etc/bluetooth/ > ?
於是,每一次cp你都要確認是不是要這麼做。只要你輸入的是y或者以y開頭的任何字串,都是確認。其他的字串是否認。另外,這兩個引數不支援{} +的格式。
OPERATORS
find的操作符(OPERATORS)實際上是用來連線多個表示式和確定其邏輯關係用的。如:
[root@zorrozou-pc0 zorro]# find /etc -name "pass*" -type f
/etc/passs/passwd
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd-
/etc/passwd
這個find命令中使用了兩個表示式,他們之間沒有任何分隔,這是實際上表達的含義是,找到兩個條件都符合的檔案。實際上就是表示式的邏輯與關係,這跟-a引數連線或者-and引數一樣:
[root@zorrozou-pc0 zorro]# find /etc -name "pass*" -a -type f
/etc/passs/passwd
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd-
/etc/passwd
[root@zorrozou-pc0 zorro]# find /etc -name "pass*" -and -type f
/etc/passs/passwd
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd-
/etc/passwd
除了邏輯與關係以外,還有邏輯或關係:
[root@zorrozou-pc0 zorro]# find /etc -name "pass*" -o -type f
[root@zorrozou-pc0 zorro]# find /etc -name "pass*" -or -type f
表示兩個條件只要符合其中一個都可以。
在條件表示式前面加!表示對錶達式取非。同樣的也可以用-not引數。另外如果表示式很多,可以使用( expr )確定優先順序,如:
[root@zorrozou-pc0 zorro]# find / ( -name "passwd" -a -type f ) -o ( -name "shadow" -a -type f )
這裡表示的是:-name “passwd” -a -type f和-name “shadow” -a -type f是或關係。
最後
find中還可能常用的其他引數比如:
-depth:制定了這個引數後,遇到目錄先進入目錄操作目錄中的檔案,最後再操作目錄本身。
-maxdepth:目錄最大深度限制。
-mindepth:目錄最小深度限制。
還有一些其他相關引數大家可以在man find中自行補充,就不在這更多廢話了。希望本篇可以對大家深入的掌握find命令有所幫助。