一、find概述
話不多說,先來find --help一下
[hive@lgh test]$ find --help Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression] #使用的語法 default path is the current directory; default expression is -print #默認是當前目錄,默認采用的action是-print,如果有設置action,則默認會被覆蓋 expression may consist of: operators, options, tests, and actions: operators (decreasing precedence; -and is implicit where no others are given): #一些重要操作,就像編程里面所用到的,與,非,或這些關系, ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2 positional options (always true): -daystart -follow -regextype #總是返回true normal options (always true, specified before other expressions): #總是返回true -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev -ignore_readdir_race -noignore_readdir_race tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N #重點 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN -readable -writable -executable -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N -used N -user NAME -xtype [bcdpfls] -context CONTEXT actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print #重點 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ; -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ; Report (and track progress on fixing) bugs via the findutils bug-reporting page at http://savannah.gnu.org/ or, if you have no web access, by sending email to <bug-findutils@gnu.org>.
從上看:find命令的使用語法:
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
其中expression主要包括operators, options, tests, and actions
expression may consist of: operators, options, tests, and actions:
二、find基本原理和實踐
find是從左向右處理的,所以表達式的前后順序不同會造成不同的搜索性能差距。
搜索機制:find的搜索機制是根據表達式返回的true/false決定的,每搜索一次都判斷一次是否能確定最終評估結果為true,只有評估的最終結果為true才算是找到。
find首先對整個命令行進行語法解析,並應用給定的options,然后定位到搜索路徑path下開始對路徑下的文件或子目錄進行表達式評估或測試,評估或測試的過程是按照表達式的順序從左向右進行的(此處不考慮操作符的影響),如果最終表達式的表達式評估為true,則輸出(默認)該文件的全路徑名
2.1、操作符(operators)
我相信大家都學過一些編程語言,這里的運算操作符合java中的編程語言一樣的意思,其實就是一些與,或,非的操作,都是一些短路的操作,雖然比較簡單,但是很有用,接下來我們具體看下這些內容:
(expr) #優先級最高。為防止括號被shell解釋(進入子shell),所以需要轉義,即\(...\) ! expr #對expr的true和false結果取反。同樣需要使用引號包圍 -not expr #等價於"! expr" expr1 expr2 #等同於and操作符。 expr1 -a expr2 #等同於and操作符。 expr1 -and expr2 #首先要求expr1為true,然后expr2以expr1搜索的結果為基礎繼續檢測,然后再返回檢測值為true的文件。因為expr2是以expr1結果為基礎的,所以如果expr1返回 #false,則expr2直接被忽略而不會進行任何操作 expr1 -o expr2 #等同於or操作符 expr1 -or expr2 #只有expr1為假時才評估expr2。 expr1 , expr2 #逗號操作符表示列表的意思,expr1和expr2都會被評估,但expr1的true或false是被無視的,只有expr2的結果才是最終狀態值。
[hive@lgh test]$ ll total 8 drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 a drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b -rw-rw-r-- 1 hive hive 0 Sep 30 10:06 c lrwxrwxrwx 1 hive hive 1 Sep 30 10:08 d -> a [hive@lgh test]$ find . -type f -a -name c #打印文件,並且名為c ./c [hive@lgh test]$ find . -type f -o -type d #打印文件或者目錄 . ./a ./b ./c
注意:and 的優先級高於 or,and和or操作都是短路操作,先判斷第一個條件,and:如果第二個條件不滿足,則第二個條件不予判讀,or則相反
2.2、選項(options)
options總是返回true。除了"-daystart",options會影響所有指定的test表達式部分,哪怕是test部分寫在options的前面。這是因為options是在命令行被解析完后立即處理的,而test是在檢測到文件后才處理的。對於"-daystart"這個選項,它們僅僅影響寫在它們后面的test部分,因此,建議將任何options部分寫在expression的最前面。
-daystart #指定以每天的開始(凌晨零點)計算關於天的時間,用於改變時間類(-amin,-atime,-cmin,-ctime,-mmin和-mtime) #的計算方式。默認天的計算是從24小時前計算的。例如,當前時間為5月3日17:00,要求搜索出2天內修改過的文件,默認 #搜索文件的起點是5月1日17:00,如果使用-daystart,則搜索文件的起點是是5月1日00:00。 #注意,該選項只會影響寫在它后面的test表達式。 -depth #搜索到目錄時,先處理目錄中的文件(子目錄),再處理目錄本身。對於"-delete"這個action,它隱含"-depth"選項。 -maxdepth levels #指定tests和actions作用的最大目錄深度,只能為非負整數。可以簡單理解為目錄搜索深度,但並非如此。當 #前path目錄的層次為1,所以若指定-maxdepth 0將得不到任何結果。 -mindepth levels #tests和actions不會應用於小於指定深度的目錄,"-mindepth 1"表示應用於所有的文件。 -ignore_readdir_race #當無法用stat檢測文件信息時(如無權限)會給出下圖所示的錯誤信息,如要忽略該信息,可以使用該選項。
[root@lgh ~]# find /etc -name passwd
/etc/passwd
/etc/pam.d/passwd
[root@lgh ~]# find /etc -maxdepth 1 -name passwd
/etc/passwd
[root@lgh ~]#
[root@lgh ~]# find /etc -maxdepth 2 -mindepth 2 -name passwd #之返回第二層目錄的匹配文件
/etc/pam.d/passwd
如果指定了-depth,則先處理目錄中的文件,再處理目錄本身。在Linux一切皆文件,子目錄也是文件
[hive@lgh test]$ ll total 8 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 1.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 2.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 3.bak drwxrwxr-x 2 hive hive 4096 Sep 30 10:52 a drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b -rw-rw-r-- 1 hive hive 0 Sep 30 10:06 c lrwxrwxrwx 1 hive hive 1 Sep 30 10:08 d -> a [hive@lgh test]$ find ../test -depth ../test/3.bak ../test/a/1.txt ../test/a/2.txt ../test/a/3.txt ../test/a #先處理目錄a下的文件,才處理a目錄 ../test/1.bak ../test/b ../test/2.bak ../test/c ../test/d ../test #最后才處理目錄
2.3、tests
(N can be +N or -N or N)
+n:大於n -n:小於n n :精確的等於n
2.3.1、從文件類型判斷
-type [bcdpflsD]
X #根據文件類型來搜索
b #塊設備文件
c #字符設備文件
d #目錄
p #命名管道文件(FIFO文件)
f #普通文件
l #符號鏈接文件,即軟鏈接文件
s #套接字文件(socket)
[hive@lgh test]$ ll total 8 drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 a drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b -rw-rw-r-- 1 hive hive 0 Sep 30 10:06 c lrwxrwxrwx 1 hive hive 1 Sep 30 10:08 d -> a [hive@lgh test]$ find . -type l #查找鏈接文件 ./d
2.3.2、從文件大小判斷
-size N[bcwkMG]
b #512字節的(默認單位)
c #1字節的
w #2字節
k #1024字節
M #1024k
G #1024M
empty:空文件,對於目錄來說,則是空目錄
[hive@lgh test]$ ll total 8 drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 a drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b -rw-rw-r-- 1 hive hive 0 Sep 30 10:06 c lrwxrwxrwx 1 hive hive 1 Sep 30 10:08 d -> a [hive@lgh test]$ find -size 1 #文件大小為1字節 ./d [hive@lgh test]$ find -size -2 #文件大小小於2字節 ./c ./d
2.3.3、從文件名后者路徑名判斷
-name pattern #文件的basename(不包括其前導目錄的純文件名)能被通配符模式的pattern匹配到。需要注意的是,在find中的通配元字符"*"、"?"和"[]"是能夠匹配以點開頭的文件的 -iname pattern #不區分大小的"-name" -path pattern #文件名能被通配符模式的pattern匹配到。此模式下,通配元字符"*"、"?"和"[]"不認為字符"/"或"."是特殊字符,也就是說這兩個字符也在通配范圍內,所以能匹配這兩個字符。 -ipath pattern #不區分大小寫的"-path" -regex pattern #文件名能被正則表達式pattern匹配到的文件。正則匹配會匹配整個路徑,例如要匹配文件名為"./fubar3" #的文件,可以使用".*bar."或".*b.*3",但不能是"f.*r3",默認find使用的正則類型是Emacs正則,但可以使用-regextype來改變正則類型 -iregex pattern #不區分大小寫的"-regex"
[hive@lgh test]$ ll total 8 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 1.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 1.txt -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 2.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 2.txt -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 3.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 3.txt -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 4.txt drwxrwxr-x 2 hive hive 4096 Sep 30 10:52 a drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b -rw-rw-r-- 1 hive hive 0 Sep 30 10:06 c lrwxrwxrwx 1 hive hive 1 Sep 30 10:08 d -> a [hive@lgh test]$ find . -name "*.bak" ./3.bak ./1.bak ./2.bak [hive@lgh test]$ find . -path "./a/*.txt" ./a/1.txt ./a/2.txt ./a/3.txt [hive@lgh test]$ find . -regex ".*txt" #正在匹配 ./1.txt ./a/1.txt ./a/2.txt ./a/3.txt ./2.txt ./4.txt ./3.txt
2.3.4、從文件權限判斷
-perm mode #精確匹配給定權限的文件。"-perm g=w"將只匹配權限為0020的文件。當然,也可以寫成三位數字的權限模式 -perm /mode #匹配任意給定權限位的權限,例如"-perm /640"可以匹配出600,040,700,740等等,只要文件權限的任意位能 #包含給定權限的任意一位就滿足 -executable #具有可執行權限的文件。它會考慮acl等的特殊權限,只要是可執行就滿足。它會忽略掉-perm的測試 -readable #具有可讀權限的文件。它會考慮acl等的特殊權限,只要是可讀就滿足。它會忽略掉-perm的測試 -writable #具有可寫權限的文件。它會考慮acl等的特殊權限,只要是可寫就滿足。它會忽略掉-perm的測試(不是writeable)
# find . -type f -perm 0777 -print # find / -type f ! -perm 777 # find / -perm 2644 # find / -perm /u=s
2.3.5、從文件所屬情況判斷
-gid n #gid為n的文件 -group gname #組名為gname的文件 -uid n #文件的所有者的uid為n -user uname #文件的所有者為uname,也可以指定uid -nogroup #匹配那些所屬組為數字格式的gid,且此gid沒有對應組名的文件 -nouser #匹配那些所有者為數字格式的uid,且此uid沒有對應用戶名的文件
# find / -user root -name tecmint.txt # find /home -user tecmint # find /home -group developer # find /home -user tecmint -iname "*.txt"
2.3.6、從文件的時間參數判斷
-anewer file:atime比mtime更接近現在的文件。也就是說,文件修改過之后被訪問過 -cnewer file:ctime比mtime更接近現在的文件 -newer file:比給定文件的mtime更接近現在的文件。 -newer[acm]t TIME:atime/ctime/mtime比時間戳TIME更新的文件 -amin n:文件的atime在范圍n分鍾內被訪問過,對這個文件運用 more、cat等命令。ls、stat命令都不會修改文件的訪問時間。注意,n可以是(+ -)n,例如-amin +3表示在3分鍾以前 -cmin n:文件的ctime在范圍n分鍾內被修改過文件的狀態,通過chmod、chown命令修改一次文件屬性,這個時間就會更新 -mmin n:文件的mtime在范圍n分鍾內被修改過內容,vim/vi修改保存 -atime n:文件的atime在范圍24*n小時內被訪問過 -ctime n:文件的ctime在范圍24*n小時內被修改狀態 -mtime n:文件的mtime在范圍24*n小時內被修改內容 -used n:最近一次ctime改變n天范圍內,atime改變過的文件,即atime比ctime晚n天的文件,可以是(+ -)n
# find / -mtime 50 # find / -atime 50 # find / -mtime +50 –mtime -100 # find / -cmin -60 # find / -mmin -60 # find / -amin -60
2.4、actions
actions部分一般都是執行某些命令,或實現某些功能。這部分是find的command line部分,注意,action是可以寫在tests表達式前面的,它並不一定是在test表達式之后執行。
-delete #刪除文件,如果刪除成功則返回true,如果刪除失敗,將給出錯誤信息。"-delete"動作隱含"-depth"。 -exec command; #注意有個分號";"結尾,該action是用於執行給定的命令。如果命令的返回狀態碼為0則該action返回true。 #command后面的所有內容都被當作command的參數,直到分號";"為止,其中參數部分使用字符串"{}"時,它 #表示find找到的文件名,即在執行命令時,"{}"會被逐一替換為find到的文件名,"{}"可以出現在參數中的 #任何位置,只要出現,它都會被文件名替換。 #注意,分號";"需要轉義,即"\;",如有需要,可以將"{}"用引號包圍起來 -ok command ; #類似於-exec,但在執行命令前會交互式進行詢問,如果不同意,則不執行命令並返回false,如果同意,則執 #行命令,但執行的命令是從/dev/null讀取輸入的 -print #總是返回true。這是默認的action,輸出搜索到文件的全路徑名,並尾隨換行符"\n"。由於在使用"-print"時所有的結 #果都有換行符,如果直接將結果通過管道傳遞給管道右邊的程序,應該要考慮到這一點:文件名中有空白字符(換行符、制表 #符、空格)將會被右邊程序誤分解,如文件"ab c.txt"將被認為是ab和c.txt兩個文件,如不想被此分解影響,可考慮使 #用"-print0"替代"-print"將所有換行符替換為"\0" -print0 #總是返回true。輸出搜索到文件的全路徑名,並尾隨空字符"\0"。由於尾隨的是空字符,所以管道傳遞給右邊的程序,然后 #只需對這個空字符進行識別分隔就能保證文件名不會因為其中的空白字符被誤分解 -prune #不進入目錄,所以可用於忽略目錄,但不會忽略普通文件。沒有給定-depth時,總是返回true,如果給定-depth,則直接 #返回false,所以-delete(隱含了-depth)是不能和-prune一起使用的 -ls #總是返回true。將找到的文件以"ls -dils"的格式打印出來,其中文件的size部分以KB為單位
[hive@lgh test]$ ll total 8 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 1.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 1.txt -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 2.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 2.txt -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 3.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 3.txt -rw-rw-r-- 1 hive hive 0 Sep 30 10:51 4.txt drwxrwxr-x 2 hive hive 4096 Sep 30 10:52 a drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b -rw-rw-r-- 1 hive hive 0 Sep 30 10:06 c lrwxrwxrwx 1 hive hive 1 Sep 30 10:08 d -> a [hive@lgh test]$ find . -type f -print -name "*.bak" #這里有一個action -print,則會覆蓋末尾默認的-print,所以在-type -f -print會把所有文件打印出來,
#然后-name "*.bak"雖然匹配到了文件,但是沒有了action,所以沒有操作顯示 ./3.bak ./1.txt ./a/1.txt ./a/2.txt ./a/3.txt ./1.bak ./2.txt ./4.txt ./2.bak ./3.txt ./c [hive@lgh test]$ find . -type f -print -name "*.bak" -ls #這個在上一種情況對 -name "*.bak"增加action -ls ,所以會把符合條件的ls出來 ./3.bak 64356992 0 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 ./3.bak ./1.txt ./a/1.txt ./a/2.txt ./a/3.txt ./1.bak 64356990 0 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 ./1.bak ./2.txt ./4.txt ./2.bak 64356991 0 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 ./2.bak ./3.txt ./c
[hive@lgh test]$ find . -name "*.txt" ./1.txt ./a/1.txt ./a/2.txt ./a/3.txt ./2.txt ./3.txt [hive@lgh test]$ find . -path "./a" -prune -o -name "*.txt" ./1.txt ./a #被忽略的目錄也在里面 ./2.txt ./3.txt
注意:如果find評估完所有表達式后發現沒有action(-prune這個action除外),則在最末尾加上-print作為默認的action。注意,這個默認的action是在評估完所有表達式后加上的。且還需注意,如果只有-prune這個action,它還是會補上-print。
常用命令:
find /backup/rman_backup/ -mtime +45 -exec rm -rf {} ; 刪除45天前的文件,這樣的命令一般可以用來刪除一些日志,或者一些臨時文件
find /tmp -mtime +7-size +1M -exec rm -rf {} ;
find -mtime +7 -nameabc* -exec rm -rf {} ;
find /tmp -mtime +7-size +1M -ok rm -rf {} ;
更多linux文章請見:linux&shell學習系列
參考:
https://www.cnblogs.com/f-ck-need-u/p/6995529.html#auto_id_5