Linux系列2:命令與文件的查找

0 引言

文件的搜尋可就厲害了!因爲我們常常需要知道那個文件放在哪裏,才能夠對該文件進行一些修改或維護等動作。 有些時候某些配置文件的文件名是不變的,但是各 版本放置的目錄則不同。 此時就得要利用一些搜尋命令將該配置檔的完整文件名找出來才能修改。

1 命令的搜索 which

1.1 which(查找命令位置)

我們知道在終端機模式當中,連續輸入兩次[tab]按鍵就能夠知道使用者有多少命令可以下達。 那你知不知道這些命令的完整檔名放在哪裏?舉例來說,ls 這個常用的命令放在哪裏呢? 就透過 which 或 type 來找尋吧!

[root@www ~]# which [-a] command
選項或參數:
-a :將所有由 PATH 目錄中可以找到的命令均列出,而不止第一個被找到的命令名稱

範例一:分別用root與一般帳號搜尋 ifconfig 這個命令的完整檔名
[root@www ~]# which ifconfig
/sbin/ifconfig            <==用 root 可以找到正確的運行檔名喔!
[root@www ~]# su - vbird <==切換身份成爲 vbird 去!
[vbird@www ~]$ which ifconfig
/usr/bin/which: no ifconfig in (/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin
:/home/vbird/bin)         <==見鬼了!竟然一般身份帳號找不到!
# 因爲 which 是根據使用者所配置的 PATH 變量內的目錄去搜尋可運行檔的!所以,
# 不同的 PATH 配置內容所找到的命令當然不一樣啦!因爲 /sbin 不在 vbird 的 
# PATH 中,找不到也是理所當然的啊!了乎?
[vbird@www ~]$ exit      <==記得將身份切換回原本的 root

範例二:用 which 去找出 which 的檔名爲何?
[root@www ~]# which which
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot '
        /usr/bin/which
# 竟然會有兩個 which ,其中一個是 alias 這玩意兒呢!那是啥?
# 那就是所謂的『命令別名』,意思是輸入 which 會等於後面接的那串命令啦!
# 更多的數據我們會在 bash 章節中再來談的!

範例三:請找出 cd 這個命令的完整檔名
[root@www ~]# which cd
/usr/bin/which: no cd in (/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin
:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin)
# 怎麼可能沒有 cd ,我明明就能夠用 root 運行 cd 的啊!

這個命令是根據『PATH』這個環境變量所規範的路徑,去查找可執行文件。 所以,重點是找出可執行文件而已!且 which 後面接的是完整的文件名!若加上 -a 選項,則可以列出所有的可以找到的同名運行檔,而非僅顯示第一個而已!
最後一個範例最有趣,怎麼 cd 這個常用的命令竟然找不到啊!爲什麼呢?這是因爲 cd 是『bash 內建的命令』啦! 但是 which 默認是找 PATH 內所規範的目錄,所以當然一定找不到的啊!那怎辦?沒關係!我們可以透過 type 這個命令喔!

1.2 type(判斷命令是否爲內建命令,查找命令)

我們使用which查找cd命令,which並沒有給出結果。因爲which只能查找path環境變量配置的路徑,而cd是bash內建命令。那麼怎麼判斷一個命令是來自於外部(指的是其他非 bash 所提供的命令) 或是內建在 bash 當中的呢?這個時候就需要使用bash的內建命令type了。


[root@www ~]# type [-tpa] name
選項與參數:
    :不加任何選項與參數時,type 會顯示出 name 是外部命令還是 bash 內建命令
-t  :當加入 -t 參數時,type 會將 name 以底下這些字眼顯示出他的意義:
      file    :表示爲外部命令;
      alias   :表示該命令爲命令別名所配置的名稱;
      builtin :表示該命令爲 bash 內建的命令功能;
-p  :如果後面接的 name 爲外部命令時,纔會顯示完整文件名;
-a  :會由 PATH 變量定義的路徑中,將所有含 name 的命令都列出來,包含 alias

範例一:查詢一下 ls 這個命令是否爲 bash 內建?
[root@www ~]# type ls
ls is aliased to `ls --color=tty' <==未加任何參數,列出 ls 的最主要使用情況
[root@www ~]# type -t ls
alias                             <==僅列出 ls 運行時的依據
[root@www ~]# type -a ls
ls is aliased to `ls --color=tty' <==最先使用 aliase
ls is /bin/ls                     <==還有找到外部命令在 /bin/ls

範例二:那麼 cd 呢?
[root@www ~]# type cd
cd is a shell builtin             <==看到了嗎? cd 是 shell 內建命令

透過 type 這個命令我們可以知道每個命令是否爲 bash 的內建命令。 此外,由於利用 type 搜尋後面的名稱時,如果後面接的名稱並不能以運行檔的狀態被找到, 那麼該名稱是不會被顯示出來的。也就是說, type 主要在找出『運行檔』而不是一般文件檔名喔! 呵呵!所以,這個 type 也可以用來作爲類似 which 命令的用途啦!找命令用的!

2 文件的搜索

再來談一談怎麼搜尋文件吧!在 Linux 底下也有相當優異的搜尋命令呦!通常 find 不很常用的!因爲速度慢之外, 也很操硬盤!通常我們都是先使用 whereis 或者是 locate 來檢查,如果真的找不到了,才以 find 來搜尋呦! 爲什麼呢?因爲 whereis 與 locate 是利用數據庫來搜尋數據,所以相當的快速,而且並沒有實際的搜尋硬盤, 比較省時間啦!

2.1 whereis(尋找特定文件)


[root@www ~]# whereis [-bmsu] 文件或目錄名
選項與參數:
-b    :只找 binary 格式的文件
-m    :只找在說明檔 manual 路徑下的文件
-s    :只找 source 來源文件
-u    :搜尋不在上述三個項目當中的其他特殊文件

範例一:請用不同的身份找出 ifconfig 這個檔名
[root@www ~]# whereis ifconfig 
ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz
[root@www ~]# su - vbird        <==切換身份成爲 vbird
[vbird@www ~]$ whereis ifconfig <==找到同樣的結果喔!
ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz
[vbird@www ~]$ exit              <==迴歸身份成爲 root 去!
# 注意看,明明 which 一般使用者找不到的 ifconfig 卻可以讓 whereis 找到!
# 這是因爲系統真的有 ifconfig 這個『文件』,但是使用者的 PATH 並沒有加入 /sbin
# 所以,未來你找不到某些命令時,先用文件搜尋命令找找看再說!

範例二:只找出跟 passwd 有關的『說明文件』檔名(man page)
[root@www ~]# whereis -m passwd
passwd: /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz

whereis 可以加入選項來找尋相關的數據, 例如如果你是要找可運行檔( binary )那麼加上 -b 就可以啦! 如果不加任何選項的話,那麼就將所有的數據列出來羅!

那麼 whereis 到底是使用什麼呢?爲何搜尋的速度會比 find 快這麼多? 其實那也沒有什麼!這是因爲whereis只找幾個特定的目錄而已,並沒有進行全文件系統查找。whereis主要是針對/bin/sbin底下的可執行文檔,以及/usr/share/man下的man page文件。不過某些文件whereis是找不到的。如果想要知道whereis到底查詢了哪些目錄,使用whereis -l來確認就行了。

2.2 locate / updatedb

[root@www ~]# locate [-ir] keyword
選項與參數:
-i  :忽略大小寫的差異;
-c  : 不輸出文檔名,僅計算找到的文件數量
-l  : 表示僅輸出幾行,例如輸出五行 -l 5
-S  : 輸出locate所使用到的數據庫文件的相關信息,包括該數據庫記錄的文件/目錄數量等
-r  :後面可接正規表示法的顯示方式
範例一:找出系統中所有與 passwd 相關的檔名,且只列出5個
[root@www ~]# locate -l 5 passwd
/etc/passwd
/etc/passwd-
/etc/pam.d/passwd
/etc/security/opasswd
/usr/bin/gpasswd
範例二:列出locate查詢所使用的數據庫文件的文件名與各數據數量
[root@www ~]# locate -S
Database /var/lib/mlocate/mlocate.db:
	8,086 directories #總共記錄的目錄數
	109,605 files #總共記錄的文件數
	5,190,295 bytes in file names
	2,349,150 bytes used to store database

這個 locate 的使用更簡單,直接在後面輸入『文件的部分名稱』後,就能夠得到結果。 舉上面的例子來說,我輸入 locate passwd ,那麼在完整檔名 (包含路徑名稱) 當中,只要有 passwd 在其中, 就會被顯示出來的!這也是個很方便好用的命令,如果你忘記某個文件的完整檔名時~~
但是,這個東西還是有使用上的限制呦!爲什麼呢?你會發現使用 locate 來尋找數據的時候特別的快, 這是因爲 locate 尋找的數據是由『已創建的數據庫 /var/lib/mlocate/』 裏面的數據所搜尋到的,所以不用直接在去硬盤當中存取數據,當然是很快速羅!
那麼有什麼限制呢?就是因爲他是經由數據庫來搜尋的,而數據庫的創建默認是在每天運行一次 (每個 distribution 都不同,CentOS 5.x 是每天升級數據庫一次!),所以當你新創建起來的文件, 卻還在數據庫升級之前搜尋該文件,那麼 locate 會告訴你『找不到!』呵呵!因爲必須要升級數據庫呀!

那能否手動升級數據庫哪?當然可以啊!升級 locate 數據庫的方法非常簡單,直接輸入『 updatedb 』就可以了! updatedb 命令會去讀取 /etc/updatedb.conf 這個配置檔的配置,然後再去硬盤裏面進行搜尋檔名的動作, 最後就升級整個數據庫文件羅!因爲 updatedb 會去搜尋硬盤,所以當你運行 updatedb 時,可能會等待數分鐘的時間喔!

  • updatedb:根據 /etc/updatedb.conf 的配置去搜尋系統硬盤內的檔名,並升級 /var/lib/mlocate 內的數據庫文件;
  • locate:依據 /var/lib/mlocate 內的數據庫記載,找出使用者輸入的關鍵字檔名。

2.3 find


[root@www ~]# find [PATH] [option] [action]
選項與參數:
1. 與時間有關的選項:共有 -atime, -ctime 與 -mtime ,以 -mtime 說明
   -mtime  n :n 爲數字,意義爲在 n 天之前的『一天之內』被更動過內容的文件;
   -mtime +n :列出在 n 天之前(不含 n 天本身)被更動過內容的文件檔名;
   -mtime -n :列出在 n 天之內(含 n 天本身)被更動過內容的文件檔名。
   -newer file :file 爲一個存在的文件,列出比 file 還要新的文件檔名

範例一:將過去系統上面 24 小時內有更動過內容 (mtime) 的文件列出
[root@www ~]# find / -mtime 0
# 那個 0 是重點!0 代表目前的時間,所以,從現在開始到 24 小時前,
# 有變動過內容的文件都會被列出來!那如果是三天前的 24 小時內?
# find / -mtime 3 有變動過的文件都被列出的意思!

範例二:尋找 /etc 底下的文件,如果文件日期比 /etc/passwd 新就列出
[root@www ~]# find /etc -newer /etc/passwd
# -newer 用在分辨兩個文件之間的新舊關係是很有用的!

時間參數真是挺有意思的!我們現在知道 atime, ctime 與 mtime 的意義,如果你想要找出一天內被更動過的文件名稱, 可以使用上述範例一的作法。但如果我想要找出『4天內被更動過的文件檔名』呢?那可以使用『 find /var -mtime -4 』。那如果是『4天前的那一天』就用『 find /var -mtime 4 』。有沒有加上『+, -』差別很大喔!我們可以用簡單的圖示來說明一下:
在這裏插入圖片描述
圖中最右邊爲目前的時間,越往左邊則代表越早之前的時間軸啦。由圖5.2.1我們可以清楚的知道:

+4代表大於等於5天前的檔名:ex> find /var -mtime +4
-4代表小於等於4天內的文件檔名:ex> find /var -mtime -4
4則是代表4-5那一天的文件檔名:ex> find /var -mtime 4
非常有趣吧!你可以在 /var/ 目錄下搜尋一下,感受一下輸出文件的差異喔!再來看看其他 find 的用法吧

選項與參數:
2. 與使用者或羣組名稱有關的參數:
   -uid n :n 爲數字,這個數字是使用者的帳號 ID,亦即 UID ,這個 UID 是記錄在
            /etc/passwd 裏面與帳號名稱對應的數字。這方面我們會在第四篇介紹。
   -gid n :n 爲數字,這個數字是羣組名稱的 ID,亦即 GID,這個 GID 記錄在
            /etc/group,相關的介紹我們會第四篇說明~
   -user name :name 爲使用者帳號名稱喔!例如 dmtsai 
   -group name:name 爲羣組名稱喔,例如 users ;
   -nouser    :尋找文件的擁有者不存在 /etc/passwd 的人!
   -nogroup   :尋找文件的擁有羣組不存在於 /etc/group 的文件!
                當你自行安裝軟件時,很可能該軟件的屬性當中並沒有文件擁有者,
                這是可能的!在這個時候,就可以使用 -nouser 與 -nogroup 搜尋。

範例三:搜尋 /home 底下屬於 vbird 的文件
[root@www ~]# find /home -user vbird
# 這個東西也很有用的~當我們要找出任何一個使用者在系統當中的所有文件時,
# 就可以利用這個命令將屬於某個使用者的所有文件都找出來喔!

範例四:搜尋系統中不屬於任何人的文件
[root@www ~]# find / -nouser
# 透過這個命令,可以輕易的就找出那些不太正常的文件。
# 如果有找到不屬於系統任何人的文件時,不要太緊張,
# 那有時候是正常的~尤其是你曾經以原始碼自行編譯軟件時。

如果你想要找出某個使用者在系統底下創建了哪些文件,使用上述的選項與參數,就能夠找出來啦! 至於那個 -nouser 或 -nogroup 的選項功能中,除了你自行由網絡上面下載文件時會發生之外, 如果你將系統裏面某個帳號刪除了,但是該帳號已經在系統內創建很多文件時,就可能會發生無主孤魂的文件存在! 此時你就得使用這個 -nouser 來找出該類型的文件羅!


選項與參數:
3. 與文件權限及名稱有關的參數:
   -name filename:搜尋文件名稱爲 filename 的文件;
   -size [+-]SIZE:搜尋比 SIZE 還要大(+)或小(-)的文件。這個 SIZE 的規格有:
                   c: 代表 byte, k: 代表 1024bytes。所以,要找比 50KB
                   還要大的文件,就是『 -size +50k 』
   -type TYPE    :搜尋文件的類型爲 TYPE 的,類型主要有:一般正規文件 (f),
                   裝置文件 (b, c), 目錄 (d), 連結檔 (l), socket (s), 
                   及 FIFO (p) 等屬性。
   -perm mode  :搜尋文件權限『剛好等於』 mode 的文件,這個 mode 爲類似 chmod
                 的屬性值,舉例來說, -rwsr-xr-x 的屬性爲 4755 !
   -perm -mode :搜尋文件權限『必須要全部囊括 mode 的權限』的文件,舉例來說,
                 我們要搜尋 -rwxr--r-- ,亦即 0744 的文件,使用 -perm -0744,
                 當一個文件的權限爲 -rwsr-xr-x ,亦即 4755 時,也會被列出來,
                 因爲 -rwsr-xr-x 的屬性已經囊括了 -rwxr--r-- 的屬性了。
   -perm +mode :搜尋文件權限『包含任一 mode 的權限』的文件,舉例來說,我們搜尋
                 -rwxr-xr-x ,亦即 -perm +755 時,但一個文件屬性爲 -rw-------
                 也會被列出來,因爲他有 -rw.... 的屬性存在!

範例五:找出檔名爲 passwd 這個文件
[root@www ~]# find / -name passwd
# 利用這個 -name 可以搜尋檔名啊!

範例六:找出 /var 目錄下,文件類型爲 Socket 的檔名有哪些?
[root@www ~]# find /var -type s
# 這個 -type 的屬性也很有幫助喔!尤其是要找出那些怪異的文件,
# 例如 socket 與 FIFO 文件,可以用 find /var -type p 或 -type s 來找!

範例七:搜尋文件當中含有 SGID 或 SUID 或 SBIT 的屬性
[root@www ~]# find / -perm +7000 
# 所謂的 7000 就是 ---s--s--t ,那麼只要含有 s 或 t 的就列出,
# 所以當然要使用 +7000 ,使用 -7000 表示要含有 ---s--s--t 的所有三個權限,
# 因此,就是 +7000 ~了乎?

上述範例中比較有趣的就屬 -perm 這個選項啦!他的重點在找出特殊權限的文件羅! 我們知道 SUID 與 SGID 都可以配置在二進位程序上,假設我想要找出來 /bin, /sbin 這兩個目錄下, 只要具有 SUID 或 SGID 就列出來該文件,你可以這樣做:

[root@www ~]# find /bin /sbin -perm +6000

因爲 SUID 是 4 分,SGID 2 分,總共爲 6 分,因此可用 +6000 來處理這個權限! 至於 find 後面可以接多個目錄來進行搜尋!另外, find 本來就會搜尋次目錄,這個特色也要特別注意喔! 最後,我們再來看一下 find 還有什麼特殊功能吧!


選項與參數:
4. 額外可進行的動作:
   -exec command :command 爲其他命令,-exec 後面可再接額外的命令來處理搜尋到
                   的結果。
   -print        :將結果列印到螢幕上,這個動作是默認動作!

範例八:將上個範例找到的文件使用 ls -l 列出來~
[root@www ~]# find / -perm +7000 -exec ls -l {} \;
# 注意到,那個 -exec 後面的 ls -l 就是額外的命令,命令不支持命令別名,
# 所以僅能使用 ls -l 不可以使用 ll 喔!注意注意!

範例九:找出系統中,大於 1MB 的文件
[root@www ~]# find / -size +1000k
# 雖然在 man page 提到可以使用 M 與 G 分別代表 MB 與 GB,
# 不過,俺卻試不出來這個功能~所以,目前應該是僅支持到 c 與 k 吧!

find 的特殊功能就是能夠進行額外的動作(action)。我們將範例八的例子以圖解來說明如下:
在這裏插入圖片描述
該範例中特殊的地方有 {} 以及 ; 還有 -exec 這個關鍵字,這些東西的意義爲:

  • {} 代表的是『由 find 找到的內容』,如上圖所示,find 的結果會被放置到 {} 位置中;
  • -exec 一直到 \; 是關鍵字,代表 find 額外動作的開始 (-exec) 到結束 (\ ; ) ,在這中間的就是 find 命令內的額外動作。 在本例中就是『 ls -l {} 』羅!
    因爲『 ; 』在 bash 環境下是有特殊意義的,因此利用反斜線來跳脫。
    透過上圖你應該就比較容易瞭解 -exec 到 ; 之間的意義了吧!

如果你要找的文件是具有特殊屬性的,例如 SUID 、文件擁有者、文件大小等等, 那麼利用 locate 是沒有辦法達成你的搜尋的!此時 find 就顯的很重要啦! 另外,find 還可以利用萬用字節來找尋檔名呢!舉例來說,你想要找出 /etc 底下檔名包含 httpd 的文件, 那麼你就可以這樣做:

[root@www ~]# find /etc -name '*httpd*'

不但可以指定搜尋的目錄(連同次目錄),並且可以利用額外的選項與參數來找到最正確的檔名!真是好好用! 不過由於 find 在尋找數據的時後相當的操硬盤!所以沒事情不要使用 find 啦!有更棒的命令可以取代呦!那就是上面提到的 whereis 與 locate 羅!

摘自:鳥哥的Linux私房菜第七章、Linux 文件與目錄管理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章