阿旺的 Linux 開竅手冊

 基礎篇    進階篇    補腦篇    指令索引  


HY-STAR's  Ads IWS's Ads


版權所有, 引用請註明出處

 基礎篇

Chapter 10 : 檔案搜尋

10.0 檔案搜尋
       type 顯示指令類型
       which 尋找執行檔
       whereis 預設路徑尋找檔案
       locate 硬碟索引搜尋
           updatedb 更新硬碟索引資料庫
       find 終極檔案搜尋






















檔案搜尋


10.0 檔案搜尋
Linux 的設計哲學之一是〝一切都是檔案〞,所以 Linux 的 filesystem 內的檔案是星雲密佈,故檔案的搜尋就顯的格外重要。還好 Linux 提供了檔案搜尋五虎將(typewhichwhereislocatefind)其檔案搜尋能力可是不輸〝谷歌大神〞。

type 顯示指令類型
type 嚴格來說並不是用來搜尋檔案,typeshell 內建的指令,用來顯示指令類型(如 shell 內建或是執行檔),但意外的副作用是用來尋找執行檔(指令)特別好用和簡單,用法如下:

語法:type [-otpiton] COMMAND
指令名稱/功能/命令使用者 選項 功能
type/
顯示指令類型/Any
-a 顯示指令所有可能的類型
-t 顯示指令的種類(alias/file or builtin)
-P 根據 PATH 找指令(類似 which)

type 優點是簡單,但缺點是只能找 shell 內建或根據環境變數 $PATH 來搜索檔案[註10.3](但實際上不一定找行檔,如非執行檔的檔案放到環境變數 PATH 的路徑是可被找到)。如不在環境變數 PATH 內的檔案會找不到,另外也不能配合萬用字元來搜尋。

例:
$ type -a pwd ←看一下指令〝pwd〞放在那個目錄
pwd is a shell builtin ←〝pwd〞其一為shell 內建
pwd is /bin/pwd ←〝pwd〞其二在〝/bin/pwd〞
$ type type ←看一下指令〝type〞放在那個目錄
type is a shell builtin ←shell 內建
$ type -a ls ←搜尋指令〝ls〞放在那個目錄
ls is aliased to `ls --color=tty' ←〝ls〞其一為〝ls --color=tty〞的別名
ls is /bin/ls ←〝ls〞其二在〝/bin/ls〞
$ type shadow ←搜尋文字檔〝shadow〞放在那個目錄
bash: type: shadow: not found ←type 一般用來找執行檔,或放到環境變數 PATH 內的檔案,否則會找不到

which 尋找執行檔
which 只能在環境變數 $PATH 內找執行檔或找別名的指令,但卻無搜尋 shell 內建的功能,是檔案搜尋五虎將中最弱的,根本是病貓,功能幾乎同等 type -fP

例: (把 type 所舉的範例用 which 再做一次)
$ which pwd ←看一下指令〝pwd〞放在那個目錄
/bin/pwd
$ which type ←找指令〝type〞
/usr/bin/which: no cd in (/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/
usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin) ← 在環境變數 PATH 內找不到〝type〞(無搜尋 shell 內建指令的功能)
$ which ls ←搜尋指令〝ls〞
alias ls='ls --color=tty' ← 執行〝ls〞實際上是執行〝ls --color=tty〞
        /bin/ls ←〝ls〞所在路徑
$ which shadow ←搜尋文字檔〝shadow〞
/usr/bin/which: no cd in (/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/
usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin) ←路徑找不到〝shadow〞

whereis 預設路徑尋找檔案
許多的書或網路上的教學都說 「 whereis 會根據資料庫來搜尋檔案,且是根據選項來找檔案類型(如找執行檔或說明文件)...」應是不正確的,反正〝天下文章一大抄〞也沒去求證。

正解〝應為〞whereis 預設用來找執行檔、原始碼和 manpage 文件,所以不同的選項搜尋路徑會不一樣(不會用到資料庫,也不管檔案類型,只要檔名匹配), 以 whereis -b 為例,會以 /bin、/sbin、/usr/bin 等存放指令的路徑搜尋檔案。

whereis
用法如下:
語法:whereis [-otpiton] COMMAND
指令名稱/功能/命令使用者 選項 功能
whereis/
(where is file)
預設路徑尋找檔案/
Any
-b 搜尋執行檔的相關路徑(/bin、/sbin、/usr/bin 等)
-B 指定搜尋執行檔路徑
-l(小寫 L) 列出搜尋的路徑
-m 搜尋說明檔的相關路徑(/usr/share/man 等)
-M 指定說明檔搜尋的路徑
-s 搜尋原始碼的相關路徑(/usr/src 等)
-S 指定原始碼搜尋的路徑

例:
$ whereis -l ←查詢 whereis 搜尋 執行檔/說明檔/原始碼 的路徑
bin: /usr/bin ←〝bin:〞開頭即為找執行檔的路徑
bin: /usr/sbin
bin: /usr/lib
bin: /etc
bin: /usr/etc
中間略
man: /usr/share/man/pl ←〝man:〞開頭即為找 man page 說明文件的路徑
man: /usr/share/man/man7
中間略
src: /usr/src/kernels ←〝src:〞開頭即為找原始碼的路徑
src: /usr/src/debug


例:
$ whereis -m zip ←搜尋〝zip〞的 man page 文件
zip: /usr/share/man/man1/zip.1.gz
$ whereis -b zip ←搜尋〝zip〞執行檔
zip: /usr/bin/zip
$ whereis -l | grep 'src:' ←列出搜尋原始碼的路徑
src: /usr/src/kernels
src: /usr/src/debug

locate 硬碟索引搜尋
因 Linux filesystem 內的檔案太多,為了加快搜尋速度所以指令 typewhichwhereis 都只搜尋各自預設的路徑,如有檔案放在家目錄〝/home/xxx〞或自建的目錄沒在上述這些指令預設搜尋的路徑內可會找不到檔案。locate 指令則利用索引資料庫〝/var/lib/mlocate/mlocate.db〞來搜尋檔案,搜尋的範圍更廣沒預設搜尋的路徑。
介紹完 locate 的基本知識,接下來來說明其語法。
語法:locate [-otpiton] file/directroy
指令名稱/功能/命令使用者 選項 功能
locate/
硬碟索引搜尋/
Any
-b 只列出符合〝基底檔名〞且可配合萬用字元搜尋
-n # 最多列出 # 個結果(〝#〞為數字)
-r 使用正規表示法搜尋
-i 忽略大小寫
-d 指定索引資料庫

原則上如要搜尋〝FILE_NAME〞,locate 會搜尋〝*FILE_NAME*〞,在檔名字串前後各加萬用字元〝*〞擴大列出的範圍,而列出 FILE_NAME 的部分可以是檔名或路徑或目錄。

例:
[aaa@localhost ~]$ locate 586 ←搜尋檔案字串〝586〞
locate: can not open `/var/lib/mlocate/mlocate.db': No such file or directory
↑ 如出現找不到〝mlocate.db〞可能還沒執行〝updatedb〞所產生的索引資料庫
[aaa@localhost ~]$ su - root ←請出〝root〞來手動更新〝updatedb〞
Password:
[root@localhost ~]# updatedb ←(會花一些時間產生索引資料庫)
[root@localhost ~]# locate 586 ←再搜尋〝586〞看看
/lib/modules/2.6.23.1-42.fc8/kernel/arch/i386/crypto/aes-i586.ko
/usr/lib/perl5/5.8.8/pod/perl586delta.pod
/usr/lib/rpm/i586-linux/macros ←路徑中有〝586〞也算
/usr/share/man/man1/perl5866delta.1.gz

如要排除找到是結果為路徑名稱,可用 locate -b 只列出符合〝基底檔名〞(basename) 的檔案或目錄,什麼是〝基底檔名〞?,以檔案〝/var/lib/mlocate/mlocate.db〞為例,排除路徑後最右邊的〝mlocate.db〞即基底檔名。

故剛才的例子 locate 586locate -b 586 再跑一次,〝/usr/lib/rpm/i586-linux/macros〞那行就不會列出。 使用 locate -b 只列出符合〝基底檔名〞另一用處為可配合萬用字元來搜尋檔案或目錄。

例:
$ locate -b apple?? ←使用〝基底檔名〞配和萬用字元搜尋字串〝apple〞
/home/aaa/.gconf/apps/panel/applets
/usr/share/terminfo/a/apple2e
/usr/share/terminfo/a/appleII

其他選項例子如下例:
$ locate -b t[!o-p]e ←使用〝基底檔名〞配和萬用字元搜尋
$ locate -i x11 ←忽略大小寫
$ locate -n 5 poweroff ←最多列出 5 個結果
$ locate -d /var/lib/mlocate/office_hd.db file ←指定索引資料庫
$ locate -r 'x\{3\}' ←使用正規表示法搜尋三個相連的〝x〞的檔案或路徑





find 終極檔案搜尋
終極檔案搜尋非 find 莫屬,除了檔名外,舉繁檔案的任何特徵如檔案大小,時間,權限,擁有者,檔案類型等都可搜尋。其哲學為:「沒有 find 找不到的檔案,除非你不會用」。

例如你硬碟快爆掉了,你想找出前 5 大最佔空間的檔案可用如下指令來找霸佔硬碟的原凶
find / -type f -exec du {} \; 2>&- | sort -n | tail -n 5

也因 find 功能強大故使用起來有點複雜,且因沒預設搜尋路徑和使用索引資料庫,而是真正把硬碟的檔案一個個翻出來找,故很花時間。

find 基本的用法為 find PATH -name 'PATTERN',如省略 PATH 則搜尋工作目錄(預設搜尋包含子目錄)。

$ find / -name 'apple??'←從根目錄開始,依樣板檔名〝apple??〞搜尋
$ find / -name 'apple??' 2> /dev/null ←同上,但濾掉錯誤輸出(常用)
/usr/src/kernels/3.10.0-693.el7.x86_64/include/config/hid/apple.h
/usr/src/kernels/3.10.0-693.el7.x86_64/include/config/backlight/apple.h
$ find /etc /usr -name "read*" ←搜尋的路徑可以不止一個

如是一般的登入者,可能沒足夠的權限進入每層目錄去搜索而產生錯誤的輸出,故畫面會很雜亂;此時可配合錯誤輸出重定向 2> /dev/null濾掉錯誤輸出,或關掉 fd stderr 寫成 find / -name 'aple??' 2>&- 輸出畫面就乾淨多了。

find 進階用法如下:
語法:find [path] [-otpiton][--option] expression
指令名稱/功能/命令使用者 選項 功能 note
find/
終極檔案搜尋/
Any
依檔案檔名或目錄或 filesystem
-name "PATTERN" 樣板(pattern)檔名搜尋 PATTEN 可配合萬用字元樣板,但只可找基底檔名(base name)即檔案去掉路徑
-iname "PATTERN" 同 -name 但不分大小寫  
-regex "PATTERN" 正規表示法搜尋 PATTEN 支援正規表示法
-regextype 變更正規表示法所支援的種類 選項有:
〝emacs〞(預設) 、〝posix-basic〞、〝posix-egrep〞、〝posix-extended〞、〝awk〞、〝grep〞、〝egrep〞等
-iregex 同 -regex 但不分大小寫  
-path "PATTERN" 路徑樣板搜尋 和選項〝 -name〞 用法類似,但選項〝 -name〞無法對路徑符號的〝/〞或〝./〞正確匹配,用此選項可克服。

-ipath "PATTERN" 同 -path 但不分大小寫  
-prune 排除 -path 或 -ipath 指定目錄內的檔案 要配合和選項〝 -path〞使用
-maxdepth # 最大搜尋 # 層目錄(# 為數字) 如 #=1,不會搜尋子目錄
-mindepth # 最少搜尋 # 層目錄(# 為數字) 如 #=1,會搜尋任一階目錄
-fstype FILESYSTEM 指定要搜尋的 filesystem 常見的 filesystem 有
Linux 的 ext2/ext3/reiserFS
DOS 的 vfat, Windows 的 ntfs (fuseblk)
CD/DVD-ROM 的〝iso9660,DVD-ROM 的 〞udf
APPLE 的 hfs,網路的 nfs 等
-xdev 只搜尋目前的 filesystem 例如根目錄掛載了不同的 filesystem,但只找和根目錄相同的 filesystem
-mount 同 -xdev  
依檔案大小
-size [+][-]#
[bckMG]
依檔案大小搜尋,可接的項目有
〝b〞:檔案所佔的 Block(磁區),Bolock=512B
〝c〞:為 byte
〝k〞:為 1024 byte
〝M〞:為 10242 byte
〝G〞:為 10243 byte

-empty 搜尋大小為 0 的檔案或空目錄  
依檔案類型
-type [bcdpfls] 檔案類型有可接的項目有
〝b〞:區塊裝置(block device)
〝c〞:字元裝置(character device)
〝d〞:目錄(directory)
〝p〞:具名管線(named pipe)
〝f〞:正規檔(regular file)
〝l〞:符號連結檔(symbolic link)
〝s〞:socket
 
-links [+][-]# 硬連結檔 # 為連結數
-follow 排除符號連結檔  
依權限或擁有者屬性
-perm[+][-]# 依權限的數字表示法搜尋  
-user OWNER_NAME 搜尋指定擁有者的檔案  
-group GROUP_NAME 搜尋指定群組的檔案  
-uid # 搜尋檔案的 UID  
-gid # 搜尋檔案的群組 GID  
-nouser 搜尋無效擁有者的檔案  
-nogroup 搜尋無效群組的檔案  
依時間
-atime[+][-]# 搜尋 atime 時間的檔案 # 單位為天
-ctime[+][-]# 搜尋 ctime 時間的檔案 # 單位為天
-mtime[+][-]# 搜尋 mtime 時間的檔案 # 單位為天
-amin 搜尋 atime 時間的檔案 # 單位為分
-cmin 搜尋 ctime 時間的檔案 # 單位為分
-mmim 搜尋 mtime 時間的檔案 # 單位為分
-anewer ref_file 搜尋比參考檔的 atime 還新的檔案  
-cnewer ref_file 搜尋比參考檔的 ctime 還新的檔案  
-newer ref_file 搜尋比參考檔的 mtime 還新的檔案  
-daystart 搜尋從本日開始算天數的檔案 單位為天,要配合 -amin,-atime,-cmin,-ctime,-mmin,-mtime 等選項
控制/執行/輸出/其他
-print 輸出到 stdout (預設值)  
-exec 指令 {} \; 將搜尋到的結果交給後續的指令  
-ok 指令 {} \; 同 -exec 但會詢問  
-delete -把搜尋到的檔案直接刪除  
-a(and) ,-o(or) -not(!) 邏輯篩選要搜尋的檔案 ,
〝-a(and)〞同〝&&〞(傳回值為 0 執行)
〝-o(or)〞同〝||
〝-not(!)〞為邏輯的 NOT(反向)
 

find 相對複雜的用法,各舉例說明,特別要注意的為如有用到〝+〞/〝-〞符號,〝+〞表示大於其大小,反之符號〝-〞表示小於其大小,如無〝+〞/〝-〞則是剛好等於其檔案的大小。

但如用在選項〝-perm〞符號〝+〞表示邏輯的 OR,而符號〝-〞表示邏輯的 AND。(邏輯的〝OR〞其一符合就成立,而邏輯〝AND〞全部都符合才成立)

^ back on top ^













[註10.3]在文字界面下輸入 echo $PATH 可查詢環境變數 PATH 在那些路徑下搜索執行檔。