標准的正則表示式格式
代碼 | 說明 |
---|---|
. | 匹配除換行符以外的任意字符 |
\w | 匹配字母或數字或下划線 |
\s | 匹配任意的空白符 |
\d | 匹配數字 |
\b | 匹配單詞的開始或結束 |
^ | 匹配字符串的開始 |
$ | 匹配字符串的結束 |
代碼/語法 | 說明 |
---|---|
* | 重復零次或更多次 |
+ | 重復一次或更多次 |
? | 重復零次或一次 |
{n} | 重復n次 |
{n,} | 重復n次或更多次 |
{n,m} | 重復n到m次 |
代碼/語法 | 說明 |
---|---|
\W | 匹配任意不是字母,數字,下划線,漢字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非數字的字符 |
\B | 匹配不是單詞開頭或結束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou這幾個字母以外的任意字符 |
擴展的正則表達式 相對標准的正則表達式 在次數表示的方面只是少了\ 其他都一樣
find支持的正則語法有emacs、posix-awk、posix-basic、posix-egrep、posix-extended
他默認使用的是 emacs 風格而非我們常用的 posix-egrep and posix-extended 格式的正則表達式
創建測試環境(模擬生產應用日志)
root@王初一:~# mkdir logs root@王初一:~# mkdir logs/2019{01..12}{01..30}
root@王初一:~# rm -rf logs/201902{29..30} root@王初一:~# for i in $(ls ~/logs/); do cd logs/$i; echo "$i TIME add logs" > access.log; touch -mt "$i"0302 access.log; cd ../..; done
find使用語法
find path -option [ -print ] [ -exec -ok command ] {} \;
查找30天之前的文件
find
正則表達式是匹配全路徑(包含文件名和相對路徑),它不是搜索。也就是說所寫的正則必須能夠匹配整個搜索目錄路徑和文件名的組合,而不是單單匹配文件名本身
root@王初一:~# find ~/logs/ -mindepth 1 -maxdepth 2 -regextype posix-extended -regex ".+\.log$" -user root -mtime +30 -type f
比如:查找當前目錄下的access.log
文件。 它的全路徑(相對路徑)是 ./access.log
, 注意前面有 ./ 而不只是文件名。所以正則可以寫成: .*log"
; 或者.*cess.*
等等,但是不能寫成ac.*og
(這里就不能匹配前面的目錄部分)
參數說明:
-maxdepth #最大深度 -mindepth #最小深度 -regextype #調用正則 -posix-extended #使用正則格式 -user #匹配屬主 -mtime #匹配時間 -type #匹配文件類型
匹配時間參數說明
atime 為 access time 即文件被讀取或者執行的時間,修改文件是不會改變access time的。 ctime 為 change time 文件狀態改變時間,指文件的i結點被修改的時間,如通過chmod修改文件屬性,ctime就會被修改。 mtime 為 modify time 指文件內容被修改的時間。 -mtime -n +n 按文件更改時間來查找文件,-n指n天以內,+n指n 天之前 -atime -n +n 按文件訪問時間來查找文件,-n指n天以內,+n指n 天之前 -ctime -n +n 按文件創建時間來查找文件,-n指n天以內,+n指n 天之前 -cmin -n +n 按文件修改時間來查找文件,-n值n分鍾以內,+n值n分鍾之前
定時清理腳本
root@王初一:~# vim clear_oldlog.sh #!/bin/bash LOG_PATH="/root/logs/" if [ -d $LOG_PATH ]; then find $LOG_PATH -mindepth 1 -maxdepth 2 -regextype posix-extended -regex ".+\.log$" -user root -mtime +30 -type f | xargs rm -rf >/dev/null 2>&1 fi
其他使用方法
-path
模糊匹配路徑
root@王初一:~# find . -path '*20190326/access.log' ./logs/20190326/access.log
-prune
-prune是一個動作項,它表示當文件是一個目錄文件時,不進入此目錄進行搜索。
要理解-prune動作,首先得理解find命令的搜索規則(也可以說find命令的算法)。
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 ./a_book_of_c.chm
那么,將上面兩個-print都替換為-prune,這兩條命令分別輸出什么?
$ find . -size +4090c -prune . $ find . -size +4096c -prune ./a_book_of_c.chm
-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>
注意:如果同時使用-depth設置項,那么-prune將被find命令忽略。man手冊頁中這么說:"If -depth is given, false; no effect."
說到這里,又得說說-depth設置項。網上好多資料說-depth設置項的功能是“在查找文件時,首先查找當前目錄中的文件,然后再在其子目錄中查找”,這明顯是錯誤的,man手冊頁中如是說:"-depth Process each directory's contents before the directory itself."。這有點像樹的后序遍歷,先遍歷當前節點的所有子節點,然后再訪問當前節點...
時間戳
文件有三個時間屬性:創建時間、最近修改時間、最近訪問時間。
最近修改時間又包括兩種,一是文件的狀態(也即權限如rwx等)最近被修改時間,一是文件的數據(也即內容)最近被修改時間。touch命令改變的即是文件數據最近被修改時間。
最近訪問時間,指的是最近一次文件數據(內容)被訪問的時間。因此,使用ls命令輸出文件的相關信息並不會修改文件的最近訪問時間。
find命令提供了針對文件的最近訪問時間、文件狀態最近被修改時間、文件數據最近被修改時間進行匹配的測試項,分別是-amin, -cmin, -mmin和-atime, -ctime, -mtime兩組,第一組基於分鍾,第二組基於天。
以-amin為例,假設當前時間tnow="2007-11-12 14:42:10"、t1="2007-11-12 14:39:10"、t2="2007-11-12 14:40:10",那么要查找最近訪問時間屬於[t1,t2]時間段的文件,可以這么寫:
$ find . -amin 3
若測試項參數是數字,則基本上都可以在數字參數前加"+"或者"-"號,表示“大於”或“小於”的意思,因此,要查找最近訪問時間屬於[t1,tnow]時間段的文件,可以這么寫:
$ find . -amin -3
"-amin n"和"-atime n"的處理方法都是:根據當前時間和文件的相應時間屬性求n值,然后比較n值和參數n,看是否符合要求。但是這個求n值的過程卻有很大不同,他們的不同也代表了兩組(基於分鍾和基於天)的不同:
"-amin n" 1、求Δt,用當前時間減去文件對應屬性的時間值即得到Δt,Δt = tnow - tfile; 2、求浮點數f,用Δt除以1分鍾,f = Δt / 1min; 3、將f的小數部分入到整數部分,得到n。即,不管f是6.0102還是6.8901,n都等於7 "-atime n" 1、求Δt,用當前時間減去文件對應屬性的時間值即得到Δt,Δt = tnow - tfile; 2、求浮點數f,用Δt處以24小時,f = Δt / 24hours; 3、將f的小數部分都舍掉,得到n。即,不管f是6.0102還是6.8901,n都等於6
權限位
用windows,從windows系統拷過來的文件經常被加上了可執行權限,比如我現在想把主目錄下所有的后綴名為.txt .pdf .rm並且具有可執行權限位的文件查找出來
權限位測試項:-perm。-perm支持符號權限位表示法也支持絕對(八進制)權限位表示法,但是最好使用八進制的權限表示法
-perm基本上有下面這幾中形式:
-perm mode File's permission bits are exactly mode. -perm -mode All of the permission bits mode are set for the file. -perm /mode Any of the permission bits mode are set for the file. -perm +mode (此形式已經不推薦使用,功能與/mode相同)
文件類型
有一個問題:我只想查找符號連接文件,可是查找結果中卻包括了普通文件、目錄文件等等,不相關的東西太多了,怎么把不是符號連接文件的查找結果去掉?
-type測試項剛好可以滿足你的要求,-type c即可,其中c表示文件類型,find中支持如下類型:
b block (buffered) special c character (unbuffered) special d directory p named pipe (FIFO) f regular file l symbolic link; s socket D door (Solaris) 針對上面的問題,可以這么寫: $ find . -name "e100*" -type l -print ./e1000 ./e100puk.txt 但是,不要這么寫: $ find -L . -name "e100*" -type l -print 加上'-L'選項之后,你將查不到需要的東西,除非符號連接已經失效了。
文件大小
-size測試項根據文件的大小查找文件,文件大小既可以用塊(block)來計量,也可以用字節來計量。默認情況下以塊計量文件大小,若想使用字節來計量只需要在數字參數后加c即可。find支持的其他計量方式有:
-size n[cwbkMG],分別表示 ‘b’ for 512-byte blocks (this is the default if no suffix is used) ‘c’ for bytes ‘w’ for two-byte words ‘k’ for Kilobytes (units of 1024 bytes) ‘M’ for Megabytes (units of 1048576 bytes) ‘G’ for Gigabytes (units of 1073741824 bytes)
用戶、用戶組
根據用戶、用戶組來查找文件,這個沒有太多要說的,記住命令格式即可:
-uid n -user username or uid -nouser -gid n -group gname or gid -nogroup
輸出格式
如果你不想查找到你想要的文件事單調的輸出文件名,你可以使用-printf動作項輸出你想要的格式,下面舉幾個-printf動作的參數:
%p 輸出文件名,包括路徑名 %f 輸出文件名,不包括路徑名 %m 以8進制方式輸出文件的權限 %g 輸出文件所屬的組 %h 輸出文件所在的目錄名 %u 輸出文件的屬主名
執行外部命令
這又是一個很容易出彩的地方。find真是強大,對查找到的文件竟然可以調用外部命令進行處理。-exec動作項就是來完成這個功能的,格式是:
find . EXPR1 -exec command {} /; 注意:后一個花括號'}'和'/'之間有一個空格。 例如,查找當前目錄下的所有普通文件,並用ls命令輸出: find . -type f -exec ls -l {} /;
使用-exec動作項處理匹配到的文件時,find命令會將所有匹配到的文件一起傳遞給exec執行。但有些系統對能夠傳遞給exec的命令長度有限制,這樣在find命令運行幾分鍾之后,就會出現溢出錯誤。錯誤信息通常是“參數列太長”或“參數列溢出”。這就是xargs命令的用處所在,特別是與find命令一起使用。
xargs的使用格式是:
find PATH EXPR1 EXPR2 | xargs command
利用管道,把find命令匹配到的文件名傳遞給xargs命令,而xargs命令每次只獲取一部分文件而不是全部。這樣它可以先處理最先獲取的一部分文件,然后是下一批,並如此繼續下去。
在有些系統中,使用-exec動作項會為處理每一個匹配到的文件而發起一個相應的進程,並非將匹配到的文件全部作為參數一次執行;這樣在有些情況下就會出現進程過多,系統性能下降的問題,因而效率不高;而使用xargs命令則只有一個進程。另外,在使用xargs命令時,究竟是一次獲取所有的參數,還是分批取得參數,以及每一次獲取參數的數目都會根據該命令的選項及系統內核中相應的可調參數來確定。
find命令配合exec和xargs可以對所匹配到的文件執行幾乎所有的命令。
擴展
查找包含指定內容的文件
[root@demo1 ~]# find ./ -type f | xargs grep "mysql is running"; ./check_mysql.sh: echo "mysql is running" [root@demo1 ~]# grep "mysql is running" check_mysql.sh echo "mysql is running"