1. 程式人生 > >Linux Shell常用技巧(七)

Linux Shell常用技巧(七)

下面給出find命令的主要應用示例:
    /> ls -l     #列出當前目錄下所包含的測試檔案
    -rw-r--r--. 1 root root 48217 Nov 12 00:57 install.log
    -rw-r--r--. 1 root root      37 Nov 12 00:56 testfile.dat
    -rw-r--r--. 1 root root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 root root     183 Nov 11 08:02 users
    -rw-r--r--. 1 root root     279 Nov 11 08:45 users2
    
    1. 按檔名查詢


    -name:  查詢時檔名大小寫敏感。
    -iname: 查詢時檔名大小寫不敏感。
    #該命令為find命令中最為常用的命令,即從當前目錄中查詢副檔名為.log的檔案。需要說明的是,預設情況下,find會從指定的目錄搜尋,並遞迴的搜尋其子目錄。
    /> find . -name "*.log"
     ./install.log
    /> find . -iname U*  
        #如果執行find . -name U*將不會找到匹配的檔案
    users users2


    2. 按檔案時間屬性查詢:
    -atime  -n[+n]: 找出檔案訪問時間在n日之內[之外]的檔案。
    -ctime  -n[+n]: 找出檔案更改時間在n日之內[之外]的檔案。
    -mtime -n[+n]:

 找出修改資料時間在n日之內[之外]的檔案。
    -amin   -n[+n]: 找出檔案訪問時間在n分鐘之內[之外]的檔案。
    -cmin   -n[+n]: 找出檔案更改時間在n分鐘之內[之外]的檔案。
    -mmin  -n[+n]: 找出修改資料時間在n分鐘之內[之外]的檔案。
    /> find -ctime -2        #找出距此時2天之內建立的檔案
    .
    ./users2
    ./install.log
    ./testfile.dat
    ./users
    ./test.tar.bz2
    /> find -ctime +2        #找出距此時2天之前建立的檔案
    沒有找到                     #因為當前目錄下所有檔案都是2天之內建立的
    /> touch install.log     #手工更新install.log的最後訪問時間,以便下面的find命令可以找出該檔案
    /> find . -cmin  -3       #找出修改狀態時間在3分鐘之內的檔案。
    install.log

    3. 基於找到的檔案執行指定的操作:
    -exec: 對匹配的檔案執行該引數所給出的shell命令。相應命令的形式為'command' {} \;,注意{}和\;之間的空格,同時兩個{}之間沒有空格
    -ok:   其主要功能和語法格式與-exec完全相同,唯一的差別是在於該選項更加安全,因為它會在每次執行shell命令之前均予以提示,只有在回答為y的時候,其後的shell命令才會被繼續執行。需要說明的是,該選項不適用於自動化指令碼,因為該提供可能會掛起整個自動化流程。
    #找出距此時2天之內建立的檔案,同時基於find的結果,應用-exec之後的命令,即ls -l,從而可以直接顯示出find找到檔案的明顯列表。
    /> find . -ctime -2 -exec ls -l {} \;
    -rw-r--r--. 1 root root      279 Nov 11 08:45 ./users2
    -rw-r--r--. 1 root root  48217 Nov 12 00:57 ./install.log
    -rw-r--r--. 1 root root        37 Nov 12 00:56 ./testfile.dat
    -rw-r--r--. 1 root root      183 Nov 11 08:02 ./users
    -rw-r--r--. 1 root root  10530 Nov 11 23:08 ./test.tar.bz2
    #找到檔名為*.log, 同時檔案資料修改時間距此時為1天之內的檔案。如果找到就刪除他們。有的時候,這樣的寫法由於是在找到之後立刻刪除,因此存在一定誤刪除的危險。
    /> ls
    install.log  testfile.dat  test.tar.bz2  users  users2
    /> find . -name "*.log" -mtime -1 -exec rm -f {} \; 
    /> ls
    testfile.dat  test.tar.bz2  users  users2
    在控制檯下,為了使上面的命令更加安全,我們可以使用-ok替換-exec,見如下示例:
    />  find . -name "*.dat" -mtime -1 -ok rm -f {} \;
    < rm ... ./testfile.dat > ? y    #對於該提示,如果回答y,找到的*.dat檔案將被刪除,這一點從下面的ls命令的結果可以看出。
    /> ls
    test.tar.bz2  users  users2

    4. 按檔案所屬的owner和group查詢:
    -user:      查詢owner屬於-user選項後面指定使用者的檔案。
    ! -user:    查詢owner不屬於-user選項後面指定使用者的檔案。
    -group:   查詢group屬於-group選項後面指定組的檔案。
    ! -group: 查詢group不屬於-group選項後面指定組的檔案。
    /> ls -l                            #下面三個檔案的owner均為root
    -rw-r--r--. 1 root root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 root root     183 Nov 11 08:02 users
    -rw-r--r--. 1 root root     279 Nov 11 08:45 users2
    /> chown stephen users   #將users檔案的owner從root改為stephen。
    /> ls -l
    -rw-r--r--. 1 root       root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 stephen root    183 Nov 11 08:02 users
    -rw-r--r--. 1 root       root     279 Nov 11 08:45 users2
    /> find . -user root          #搜尋owner是root的檔案
    .
    ./users2
    ./test.tar.bz2
    /> find . ! -user root        #搜尋owner不是root的檔案,注意!和-user之間要有空格。
    ./users
    /> ls -l                            #下面三個檔案的所屬組均為root
    -rw-r--r--. 1 root      root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 stephen root    183 Nov 11 08:02 users
    -rw-r--r--. 1 root      root    279 Nov 11 08:45 users2
    /> chgrp stephen users    #將users檔案的所屬組從root改為stephen
    /> ls -l
    -rw-r--r--. 1 root           root    10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 stephen stephen      183 Nov 11 08:02 users
    -rw-r--r--. 1 root            root       279 Nov 11 08:45 users2
    /> find . -group root        #搜尋所屬組是root的檔案
    .
    ./users2
    ./test.tar.bz2
    /> find . ! -group root      #搜尋所屬組不是root的檔案,注意!和-user之間要有空格。    
    ./users

    5. 按指定目錄深度查詢:
    -maxdepth: 後面的引數表示距當前目錄指定的深度,其中1表示當前目錄,2表示一級子目錄,以此類推。在指定該選項後,find只是在找到指定深度後就不在遞迴其子目錄了。下例中的深度為1,表示只是在當前子目錄中搜索。如果沒有設定該選項,find將遞迴當前目錄下的所有子目錄。
    /> mkdir subdir               #建立一個子目錄,並在該子目錄內建立一個檔案
    /> cd subdir
    /> touch testfile
    /> cd ..
    #maxdepth後面的引數表示距當前目錄指定的深度,其中1表示當前目錄,2表示一級子目錄,以此類推。在指定該選項後,find只是在找到指定深度後就不在遞迴其子目錄了。下例中的深度為1,表示只是在當前子目錄中搜索。如果沒有設定該選項,find將遞迴當前目錄下的所有子目錄。
    /> find . -maxdepth 1 -name "*"
    .
    ./users2
    ./subdir
    ./users
    ./test.tar.bz2
    #搜尋深度為子一級子目錄,這裡可以看出子目錄下剛剛建立的testfile已經被找到
    /> find . -maxdepth 2 -name "*"  
    .
    ./users2
    ./subdir
    ./subdir/testfile
    ./users
    ./test.tar.bz2
    
    6. 排除指定子目錄查詢:
    -path pathname -prune:   避開指定子目錄pathname查詢。
    -path expression -prune:  避開表達中指定的一組pathname查詢。
    需要說明的是,如果同時使用-depth選項,那麼-prune將被find命令忽略。
    #為後面的示例建立需要避開的和不需要避開的子目錄,並在這些子目錄內均建立符合查詢規則的檔案。
    /> mkdir DontSearchPath  
    /> cd DontSearchPath
    /> touch datafile1
    /> cd ..
    /> mkdir DoSearchPath
    /> cd DoSearchPath
    /> touch datafile2
    /> cd ..
    /> touch datafile3
    #當前目錄下,避開DontSearchPath子目錄,搜尋所有檔名為datafile*的檔案。
    /> find . -path "./DontSearchPath" -prune -o -name "datafile*" -print
    ./DoSearchPath/datafile2
    ./datafile3
    #當前目錄下,同時避開DontSearchPath和DoSearchPath兩個子目錄,搜尋所有檔名為datafile*的檔案。
    /> find . \( -path "./DontSearchPath" -o -path "./DoSearchPath" \) -prune -o -name "datafile*" -print
    ./datafile3
        
    7. 按檔案許可權屬性查詢:
    -perm mode:   檔案許可權正好符合mode(mode為檔案許可權的八進位制表示)。
    -perm +mode: 檔案許可權部分符合mode。如命令引數為644(-rw-r--r--),那麼只要檔案許可權屬性中有任何許可權和644重疊,這樣的檔案均可以被選出。
    -perm -mode:  檔案許可權完全符合mode。如命令引數為644(-rw-r--r--),當644中指定的許可權已經被當前檔案完全擁有,同時該檔案還擁有額外的許可權屬性,這樣的檔案可被選出。
    /> ls -l
    -rw-r--r--. 1 root            root           0 Nov 12 10:02 datafile3
    -rw-r--r--. 1 root            root    10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 stephen stephen        183 Nov 11 08:02 users
    -rw-r--r--. 1 root            root        279 Nov 11 08:45 users2
    /> find . -perm 644      #查詢所有檔案許可權正好為644(-rw-r--r--)的檔案。
    ./users2
    ./datafile3
    ./users
    ./test.tar.bz2
    /> find . -perm 444      #當前目錄下沒有檔案的許可權屬於等於444(均為644)。    
    /> find . -perm -444     #644所包含的許可權完全覆蓋444所表示的許可權。
    .
    ./users2
    ./datafile3
    ./users
    ./test.tar.bz2
    /> find . -perm +111    #查詢所有可執行的檔案,該命令沒有找到任何檔案。
    /> chmod u+x users     #改變users檔案的許可權,新增owner的可執行許可權,以便於下面的命令可以將其找出。
    /> find . -perm +111     
    .
    ./users    
    
    8. 按檔案型別查詢:
    -type:後面指定檔案的型別。
    b - 塊裝置檔案。
    d - 目錄。
    c - 字元裝置檔案。
    p - 管道檔案。
    l  - 符號連結檔案。
    f  - 普通檔案。
    /> mkdir subdir 
    /> find . -type d      #在當前目錄下,找出檔案型別為目錄的檔案。
    ./subdir
  /> find . ! -type d    #在當前目錄下,找出檔案型別不為目錄的檔案。
    ./users2
    ./datafile3
    ./users
    ./test.tar.bz2
    /> find . -type f       #在當前目錄下,找出檔案型別為檔案的檔案
    ./users2
    ./datafile3
    ./users
    ./test.tar.bz2
    
    9. 按檔案大小查詢:
    -size [+/-]100[c/k/M/G]: 表示檔案的長度為等於[大於/小於]100塊[位元組/k/M/G]的檔案。
    -empty: 查詢空檔案。
    /> find . -size +4k -exec ls -l {} \;  #查詢檔案大小大於4k的檔案,同時打印出找到檔案的明細
    -rw-r--r--. 1 root root 10530 Nov 11 23:08 ./test.tar.bz2
    /> find . -size -4k -exec ls -l {} \;  #查詢檔案大小小於4k的檔案。
    -rw-r--r--. 1 root            root 279 Nov 11 08:45 ./users2
    -rw-r--r--. 1 root             root    0 Nov 12 10:02 ./datafile3
    -rwxr--r--. 1 stephen stephen 183 Nov 11 08:02 ./users
    /> find . -size 183c -exec ls -l {} \; #查詢檔案大小等於183位元組的檔案。
    -rwxr--r--. 1 stephen stephen 183 Nov 11 08:02 ./users
    /> find . -empty  -type f -exec ls -l {} \;
    -rw-r--r--. 1 root root 0 Nov 12 10:02 ./datafile3
    
    10. 按更改時間比指定檔案新或比檔案舊的方式查詢:
    -newer file1 ! file2: 查詢檔案的更改日期比file1新,但是比file2老的檔案。
    /> ls -lrt   #以時間順序(從早到晚)列出當前目錄下所有檔案的明細列表,以供後面的例子參考。
    -rwxr--r--. 1 stephen stephen   183 Nov 11 08:02 users1
    -rw-r--r--. 1 root           root    279 Nov 11 08:45 users2
    -rw-r--r--. 1 root           root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 root           root        0 Nov 12 10:02 datafile3
    /> find . -newer users1     #查詢檔案更改日期比users1新的檔案,從上面結果可以看出,其餘檔案均符合要求。
    ./users2
    ./datafile3
    ./test.tar.bz2
    /> find . ! -newer users2   #查詢檔案更改日期不比users1新的檔案。
    ./users2
    ./users
    #查詢檔案更改日期比users2新,但是不比test.tar.bz2新的檔案。
    /> find . -newer users2 ! -newer test.tar.bz2
    ./test.tar.bz2
    
    細心的讀者可能發現,關於find的說明,在我之前的Blog中已經給出,這裡之所以拿出一個小節再次講述該命令主要是因為以下三點原因:
    1. find命令在Linux Shell中扮演著極為重要的角色;
    2. 為了保證本系列的完整性;
    3. 之前的Blog是我多年之前留下的總結筆記,多少有些粗糙,這裡給出了更為詳細的舉例。

 

十七. xargs命令:

    該命令的主要功能是從輸入中構建和執行shell命令。       
    在使用find命令的-exec選項處理匹配到的檔案時, find命令將所有匹配到的檔案一起傳遞給exec執行。但有些系統對能夠傳遞給exec的命令長度有限制,這樣在find命令執行幾分鐘之後,就會出現溢位錯誤。錯誤資訊通常是“引數列太長”或“引數列溢位”。這就是xargs命令的用處所在,特別是與find命令一起使用。  
    find命令把匹配到的檔案傳遞給xargs命令,而xargs命令每次只獲取一部分檔案而不是全部,不像-exec選項那樣。這樣它可以先處理最先獲取的一部分檔案,然後是下一批,並如此繼續下去。  
    在有些系統中,使用-exec選項會為處理每一個匹配到的檔案而發起一個相應的程序,並非將匹配到的檔案全部作為引數一次執行;這樣在有些情況下就會出現程序過多,系統性能下降的問題,因而效率不高;  
    而使用xargs命令則只有一個程序。另外,在使用xargs命令時,究竟是一次獲取所有的引數,還是分批取得引數,以及每一次獲取引數的數目都會根據該命令的選項及系統核心中相應的可調引數來確定。
    /> ls -l
    -rw-r--r--. 1 root root        0 Nov 12 10:02 datafile3
    -rw-r--r--. 1 root root 10530 Nov 11 23:08 test.tar.bz2
    -rwxr--r--. 1 root root    183 Nov 11 08:02 users
    -rw-r--r--. 1 root root    279 Nov 11 08:45 users2
    #查詢當前目錄下的每一個普通檔案,然後使用xargs命令來測試它們分別屬於哪類檔案。
    /> find . -type f -print | xargs file 
    ./users2:        ASCII text
    ./datafile3:      empty
    ./users:          ASCII text
    ./test.tar.bz2: bzip2 compressed data, block size = 900k
    #回收當前目錄下所有普通檔案的執行許可權。
    /> find . -type f -print | xargs chmod a-x
    /> ls -l
    -rw-r--r--. 1 root root     0 Nov 12 10:02 datafile3
    -rw-r--r--. 1 root root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 root root   183 Nov 11 08:02 users
    -rw-r--r--. 1 root root   279 Nov 11 08:45 users2
    #在當面目錄下查詢所有普通檔案,並用grep命令在搜尋到的檔案中查詢hostname這個詞
    /> find . -type f -print | xargs grep "hostname" 
    #在整個系統中查詢記憶體資訊轉儲檔案(core dump) ,然後把結果儲存到/tmp/core.log 檔案中。
    /> find / -name "core" -print | xargs echo "" >/tmp/core.log  

    /> pgrep mysql | xargs kill -9  #直接殺掉mysql的程序
    [1]+  Killed              &nb