本文已不再維護,更新文章請參考此處
在前一章節裡面我們認識了 Linux 系統下的檔案權限概念以及目錄的配置說明。 在這個章節當中,我們就直接來進一步的操作與管理檔案與目錄吧!包括在不同的目錄間變換、 建立與刪除目錄、建立與刪除檔案,還有尋找檔案、查閱檔案內容等等, 都會在這個章節作個簡單的介紹啊!

1. 目錄與路徑
  1.1 相對路徑與絕對路徑
  1.2 目錄的相關操作cd, pwd, mkdir, rmdir
  1.3 關於執行檔路徑的變數: $PATH
2. 檔案與目錄管理
  2.1 檔案與目錄的檢視: ls
  2.2 複製、移動與刪除: cp, rm, mv
  2.3 取得路徑的檔案名稱與目錄名稱
3. 檔案內容查閱:
  3.1 直接檢視檔案內容cat, tac, nl
  3.2 可翻頁檢視more, less
  3.3 資料擷取head, tail
  3.4 非純文字檔: od
  3.5 修改檔案時間與建置新檔: touch
4. 檔案與目錄的預設權限與隱藏權限
  4.1 檔案預設權限:umask
  4.2 檔案隱藏屬性: chattr, lsattr
  4.4 檔案特殊權限:SUID/SGID/Sticky Bit
  4.3 檔案類型:file
5. 檔案的搜尋:which, whereis, locate, find
6. 本章習題練習
7. 針對本文的建議:http://phorum.vbird.org/viewtopic.php?t=23879

目錄與路徑:
由前一章節『Linux 的檔案權限與目錄配置』中約略瞭解到 Linux 的『樹狀目錄』概念之後,接下來就得要實際的來搞定一些基本的路徑問題了!這些目錄的問題當中, 最重要的莫過於『絕對路徑』與『相對路徑』的意義啦!趕緊來瞭解一下!


相對路徑與絕對路徑:
在開始目錄的切換之前,你必須要先瞭解一下所謂的『路徑 (PATH)』, 有趣的是:什麼是『相對路徑』與『絕對路徑』? 雖然前一章已經稍微針對這個議題提過一次,不過,這裡不厭其煩的再次的強調一下!

如果你還記得前一章的內容的話,那麼應該還記得 Linux 裡面的目錄是呈現『樹狀目錄』 的情況,就是有分支的啦!好了,假設你需要在任意一個目錄下變換到根目錄的 etc 底下,那麼你就應該要使用『 cd /etc 』這個情況, 這也就是所謂的『絕對路徑』,他是從根目錄連續寫上來的一個情況, 所以不論你在哪一個路徑現執行這一個指令,都會將你移動到該路徑下。那如果我是使用 『cd etc 』呢?那表示你要切換到『目前這個目錄下的 etc 目錄中』,情況可是不一樣的呦!通常第一次接觸 Linux 的使用者常會搞錯這一個路徑的觀念! 那麼相對路徑與絕對路徑有什麼了不起呀!?喝!那可真的是了不起了!假設您寫了一個套件, 這個套件共需要三個目錄,分別是 etc, bin, man 這三個目錄,然而由於不同的人喜歡安裝在不同的目錄之下, 假設甲安裝的目錄是 /usr/local/packages/etc, /usr/local/packages/bin 及 /usr/local/packages/man ,不過乙卻喜歡安裝在 /home/packages/etc, /home/packages/bin, /home/packages/man 這三個目錄中,請問如果需要用到絕對路徑的話,那麼是否很麻煩呢?是的! 如此一來每個目錄下的東西就很難對應的起來!這個時候相對路徑的寫法就顯的特別的重要了!

此外,如果您跟鳥哥一樣,喜歡將路徑的名字寫的很長,好讓自己知道那個目錄是在幹什麼的,例如: /data4/staiwan19961109/models-3/smoke 這個目錄,而另一個目錄在 /data4/staiwan19961109/models-3/cctm ,那麼我從第一個要到第二個目錄去的話,怎麼寫比較方便? 當然是『 cd ../cctm 』比較方便囉!對吧!

但是對於檔案的正確性來說,『絕對路徑的正確度要比較好∼』。 一般來說,鳥哥會建議您,如果是在寫程式 (shell scripts) 的條件下,務必使用絕對路徑的寫法。 怎麼說呢?因為絕對路徑的寫法雖然比較麻煩,但是可以肯定這個寫法絕對不會有問題。 如果使用相對路徑在程式當中,則可能由於您執行的工作環境不同,導致一些問題的發生。 這個問題在例行性命令當中尤其重要!這個現象我們在 shell script 時,會再次的提醒您喔! ^_^

目錄的相關操作:
在之前我們稍微提到這個變換目錄的指令是 cd ,還有哪些可以進行目錄操作的指令呢? 例如建立目錄啊、刪除目錄之類的∼還有,得要先知道的,就是有哪些比較特殊的目錄呢? 舉例來說,底下這些就是比較特殊的目錄,得要用力的記下來才行:
.         代表此層目錄
..        代表上一層目錄
-         代表前一個工作目錄
~         代表『目前使用者身份』所在的家目錄
~account  代表 account 這個使用者的家目錄
在目錄底下有兩個目錄是一定會存在的!那就是 . 與 .. 囉∼ 分別代表此層與上層目錄的意思。那我們在前一章 Linux 檔案屬性與目錄配置 裡面也知道根目錄 (/) 是所有目錄的最頂層,那麼 / 有 .. 嗎?!您可以使用 ls -al / 去看看, 答案是『有的!』不過,您也可以查閱到,根目錄的 . 與 .. 屬性完全一模一樣,哈哈! 原來根目錄的頂層 (..) 與他自己 (.) 是同一個目錄啦! ^_^

底下我們就來談一談幾個常見的處理目錄的指令吧:
  • cd:變換目錄
  • pwd:顯示目前的目錄
  • mkdir:建立一個新的目錄
  • rmdir:刪除一個空的目錄

  • cd (變換目錄)
  • 我們知道 dmtsai 這個使用者的家目錄是 /home/dmtsai ,而 root 家目錄則是 /root ,假設我以 root 身份在 Linux 系統中,那麼簡單的說明一下這幾個特殊的目錄的意義是:
    [root@linux ~]# cd [相對路徑或絕對路徑]
    # 最重要的就是目錄的絕對路徑與相對路徑,還有一些特殊目錄的符號囉!
    [root@linux ~]# cd ~dmtsai
    # 代表去到 dmtsai 這個使用者的家目錄,亦即 /home/dmtsai
    [root@linux dmtsai]# cd ~
    # 表示回到自己的家目錄,亦即是 /root 這個目錄
    [root@linux ~]# cd
    # 沒有加上任何路徑,也還是代表回到自己家目錄的意思喔!
    [root@linux ~]# cd ..
    # 表示去到目前的上層目錄,亦即是 /root 的上層目錄的意思;
    [root@linux /]# cd -
    # 表示回到剛剛的那個目錄,也就是 /root 囉∼
    [root@linux ~]# cd /var/spool/mail
    # 這個就是絕對路徑的寫法!直接指定要去的完整路徑名稱!
    [root@linux mail]# cd ../mqueue
    # 這個是相對路徑的寫法,我們由 /var/spool/mail 去到 /var/spool/mqueue 就這樣寫!
    
    cd 是 Change Directory 的縮寫,這是用來變換工作目錄的指令。注意,目錄名稱與 cd 指令之間存在一個空格。 一登入 Linux 系統後,root 會在 root 的家目錄,亦即 /root 下,OK!那回到上一層目錄可以用『 cd .. 』。 利用相對路徑的寫法必須要確認您目前的路徑才能正確的去到想要去的目錄。例如上表當中最後一個例子, 您必須要確認您是在 /var/spool/mail 當中,並且知道在 /var/spool 當中有個 mqueue 的目錄才行啊∼ 這樣才能使用 cd ../mqueue 去到正確的目錄說,否則就要直接輸入 cd /var/spool/mqueue 囉∼

    其實,我們的提示字元,亦即那個 [root@linux ~]# 當中,就已經有指出目前的目錄了, 剛登入時會到自己的家目錄,而家目錄還有一個代碼,那就是『 ~ 』符號! 例如上面的例子可以發現,使用『 cd ~ 』可以回到個人的家目錄裡頭去呢! 另外,針對 cd 的使用方法,如果僅輸入 cd 時,代表的就是『 cd ~ 』的意思喔∼ 亦即是會回到自己的家目錄啦!而那個『 cd - 』比較難以理解,請自行多做幾次練習, 就會比較明白了。
    還是要一再地提醒,我們的 Linux 的預設指令列模式 (bash shell) 具有檔案補齊功能, 您要常常利用 [tab] 按鍵來達成您的目錄完整性啊!這可是個好習慣啊∼ 可以避免您按錯鍵盤輸入錯字說∼ ^_^

  • pwd (顯示目前所在的目錄)
  • [root@linux ~]# pwd [-P]
    參數:
    -P  :顯示出確實的路徑,而非使用連結 (link) 路徑。
    範例:
    [root@linux ~]# pwd
    /root   <== 顯示出目錄啦∼
    [root@linux ~]# cd /var/mail
    [root@linux mail]# pwd
    /var/mail
    [root@linux mail]# pwd -P
    /var/spool/mail   <== 怎麼回事?有沒有加 -P 差很多∼
    [root@linux mail]# ls -l /var/mail
    lrwxrwxrwx  1 root root 10 Jun 25 08:25 /var/mail -> spool/mail
    # 看到這裡應該知道為啥了吧?因為 /var/mail 是連結檔,連結到 /var/spool/mail 
    # 所以,加上 pwd -P 的參數後,會不以連結檔的資料顯示,而是顯示正確的完整路徑啊!
    
    pwd 是 Print Working Directory 的縮寫,也就是顯示目前所在目錄的指令, 例如在上個表格最後的目錄是 /var/mail 這個目錄,但是提示字元僅顯示 mail, 如果你想要知道目前所在的目錄,可以輸入 pwd 即可。此外,由於很多的套件所使用的目錄名稱都相同,例如 /usr/local/etc 還有 /etc ,但是通常 Linux 僅列出最後面那一個目錄而已,這個時候你就可以使用 pwd 來知道你的所在目錄囉!免得搞錯目錄,結果……

    其實有趣的是那個 -P 的參數啦!他可以讓我們取得正確的目錄名稱,而不是以連結檔的路徑來顯示的。 如果您是 Fedora Core 4 的話,剛剛好, /var/mail 是 /var/spool/mail 的連結檔, 所以,透過到 /var/mail 下達 pwd -P 就能夠知道這個參數的意義囉∼ ^_^


  • mkdir (建立新目錄)
  • [root@linux ~]# mkdir [-mp] 目錄名稱
    參數:
    -m :設定檔案的權限喔!直接設定,不需要看預設權限 (umask) 的臉色∼
    -p :幫助你直接將所需要的目錄遞迴建立起來!
    範例:
    [root@linux ~]# cd /tmp
    [root@linux tmp]# mkdir test    <== 建立一名為 test 的新目錄
    [root@linux tmp]# mkdir test1/test2/test3/test4
    mkdir: cannot create directory `test1/test2/test3/test4': 
    No such file or directory  <== 沒辦法直接建立此目錄啊!
    [root@linux tmp]# mkdir -p test1/test2/test3/test4
    # 加了這個 -p 的參數,可以自行幫您建立多層目錄!
    [root@linux tmp]# mkdir -m 711 test2
    [root@linux tmp]# ls -l
    drwxr-xr-x  3 root  root 4096 Jul 18 12:50 test
    drwxr-xr-x  3 root  root 4096 Jul 18 12:53 test1
    drwx--x--x  2 root  root 4096 Jul 18 12:54 test2
    # 仔細看上面的權限部分,如果沒有加上 -m 來強制設定屬性,系統會使用預設屬性。
    # 那麼您的預設屬性為何?這要透過底下介紹的 umask 才能瞭解喔! ^_^
    
    如果想要建立新的目錄的話,那麼就使用 mkdir (make directory) 吧! 不過,請注意呦!在預設的情況下, 你所需要的目錄得一層一層的建立才行!例如:假如你要建立一個目錄為 /home/bird/testing/test1,那麼首先必須要有 /home 然後 /home/bird ,再來 /home/bird/testing 都必須要存在,才可以建立 /home/bird/testing/test1 這個目錄!假如沒有 /home/bird/testing 時,就沒有辦法建立 test1 的目錄囉!不過,現在有個更簡單有效的方法啦!那就是加上 -p 這個參數喔!你可以直接下達:『 mkdir -p /home/bird/testing/test1 』 則系統會自動的幫你將 /home, /home/bird, /home/bird/testing 依序的建立起目錄!並且, 如果該目錄本來就已經存在時,系統也不會顯示錯誤訊息喔!挺快樂的吧! ^_^

    另外,有個地方您必須要先有概念,那就是『預設權限』的地方。我們可以利用 -m 來強制給予一個新的目錄相關的屬性, 例如上表當中,我們給予 -m 711 來給予新的目錄 drwx--x--x 的屬性。不過,如果沒有給予 -m 屬性時, 那麼預設的新建目錄屬性又是什麼呢?這個跟 umask 有關,我們在後頭會加以介紹的。


  • rmdir (刪除『空』的目錄)
  • [root@linux ~]# rmdir [-p] 目錄名稱
    參數:
    -p :連同上層『空的』目錄也一起刪除
    範例:
    [root@linux tmp]# ls -l
    drwxr-xr-x  3 root  root 4096 Jul 18 12:50 test
    drwxr-xr-x  3 root  root 4096 Jul 18 12:53 test1
    drwx--x--x  2 root  root 4096 Jul 18 12:54 test2
    [root@linux tmp]# rmdir test
    [root@linux tmp]# rmdir test1
    rmdir: `test1': Directory not empty
    [root@linux tmp]# rmdir -p test1/test2/test3/test4
    [root@linux tmp]# ls -l
    drwx--x--x  2 root  root 4096 Jul 18 12:54 test2
    # 瞧!利用 -p 這個參數,立刻就可以將 test1/test2/test3/test4 一次刪除∼
    # 不過要注意的是,這個 rmdir 僅能『刪除空的目錄』喔!
    
    如果想要建立刪除舊有的目錄時,就使用 rmdir 吧!例如將剛剛建立的 test 殺掉,使用 rmdir test 即可!請注意呦!目錄需要一層一層的刪除才行!而且 被刪除的目錄裡面必定不能還有其他的目錄或檔案! 這也是所謂的空的目錄 (empty directory) 的意思啊!那如果要將所有目錄下的東西都殺掉呢?! 這個時候就必須使用 rm -rf test 囉!不過,還是使用 rmdir 比較不危險!不過,你也可以嘗試以 -p 的參數加入,來刪除上層的目錄喔!

    關於執行檔路徑的變數: $PATH
    在提過了絕對路徑、相對路徑與指令的下達方式之後,您應該會稍微注意到一件事情,那就是:『 為什麼我可以在任何地方執行 /bin/ls 這個指令呢? 』對呀! 為什麼我可以直接執行 ls 就一定可以顯示出一些訊息而不會說找不到該 /bin/ls 指令呢? 這是因為環境變數 PATH 的幫助所致呀!當我們在執行一個指令的時候, 系統會依照 PATH 的設定去每個 PATH 定義的路徑下搜尋執行檔,先搜尋到的指令先被執行之!現在,請下達 echo $PATH , echo 有『顯示、印出』的意思,而 PATH 前面加的 $ 表示後面接的是變數,所以即會顯示出目前的 PATH 了!
    [root@linux ~]# echo $PATH
    /sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin
    
    注意到了嗎?對啦! /bin 在 PATH 的設定之中,所以自然就可以找的到 ls 啦! PATH 對於執行檔來說,是個很重要的『變數』,他主要是用來規範指令搜尋的目錄。 而每個目錄是有順序的,每個目錄中間以冒號『:』來分隔,就如同上面範例中提到的囉! 那麼 PATH 這個變數還有什麼地方重要呢? 關於更多的 PATH 與相關的『變數』及『環境變數』概念,我們會在第三篇 bash shell 時, 再更深入的介紹囉∼而經過上面的說明,您應該也能夠比較瞭解的是:『 為什麼絕對路徑下達指令的方法比相對路徑要正確的多 』這句話的意義囉∼ ^_^ 因為是直接找到該指令來執行,而不是透過 PATH 這個變數的內容去搜尋的啊!

    檔案與目錄管理:
    談了談目錄與路徑之後,再來討論一下關於檔案的一些基本管理吧!檔案與目錄的管理上,不外乎『顯示屬性』、 『拷貝』、『刪除檔案』及『移動檔案或目錄』等等,由於檔案與目錄的管理在 Linux 當中是很重要的! 尤其是每個人自己家目錄的資料也都需要注意管理!由於我們在執行程式的時後,系統預設有一個搜尋的路徑順序, 如果有兩個以上相同檔名的執行檔分別在不同的路徑時,呵呵,就需要特別留意囉! 這裡我們來談一談有關檔案與目錄的一些基礎管理部分吧!


    檔案與目錄的檢視: ls
    [root@linux ~]# ls [-aAdfFhilRS] 目錄名稱
    [root@linux ~]# ls [--color={none,auto,always}] 目錄名稱
    [root@linux ~]# ls [--full-time] 目錄名稱
    參數:
    -a  :全部的檔案,連同隱藏檔( 開頭為 . 的檔案) 一起列出來∼
    -A  :全部的檔案,連同隱藏檔,但不包括 . 與 .. 這兩個目錄,一起列出來∼
    -d  :僅列出目錄本身,而不是列出目錄內的檔案資料
    -f  :直接列出結果,而不進行排序 (ls 預設會以檔名排序!)
    -F  :根據檔案、目錄等資訊,給予附加資料結構,例如:
          *:代表可執行檔; /:代表目錄; =:代表 socket 檔案; |:代表 FIFO 檔案;
    -h  :將檔案容量以人類較易讀的方式(例如 GB, KB 等等)列出來;
    -i  :列出 inode 位置,而非列出檔案屬性;
    -l  :長資料串列出,包含檔案的屬性等等資料;
    -n  :列出 UID 與 GID 而非使用者與群組的名稱 (UID與GID會在帳號管理提到!)
    -r  :將排序結果反向輸出,例如:原本檔名由小到大,反向則為由大到小;
    -R  :連同子目錄內容一起列出來;
    -S  :以檔案容量大小排序!
    -t  :依時間排序
    --color=never  :不要依據檔案特性給予顏色顯示;
    --color=always :顯示顏色
    --color=auto   :讓系統自行依據設定來判斷是否給予顏色
    --full-time    :以完整時間模式 (包含年、月、日、時、分) 輸出
    --time={atime,ctime} :輸出 access 時間或 改變權限屬性時間 (ctime) 
                           而非內容變更時間 (modification time)
    範例:
    
    在 Linux 系統當中,這個 ls 指令可能是最常被執行的吧!因為我們隨時都要知道檔案或者是目錄的相關資訊啊∼ 不過,我們 Linux 的檔案所記錄的資訊實在是太多了, ls 沒有需要全部都列出來呢∼ 所以,當您只有下達 ls 時,預設顯示的只有:非隱藏檔的檔名、 以檔名進行排序及檔名代表的顏色顯示;如此而已。舉例來說, 您下達 ls /etc 之後,只有經過排序的檔名以及以藍色顯示目錄及白色顯示一般檔案,如此而已。

    那如果我還想要加入其他的顯示資訊時,可以加入上頭提到的那些有用的參數呢∼ 舉例來說,我們之前一直用到的 -l 這個長串顯示資料內容,以及將隱藏檔也一起列示出來的 -a 參數等等。
    範例一:將家目錄下的所有檔案列出來(含屬性與隱藏檔)
    [root@linux ~]# ls -al ~
    total 252
    drwxr-x---   9 root root  4096 Jul 16 23:40 .
    drwxr-xr-x  24 root root  4096 Jul 16 23:45 ..
    -rw-------   1 root root  1491 Jun 25 08:53 anaconda-ks.cfg
    -rw-------   1 root root 12543 Jul 18 01:23 .bash_history
    -rw-r--r--   1 root root    24 Dec  4  2004 .bash_logout
    -rw-r--r--   1 root root   191 Dec  4  2004 .bash_profile
    -rw-r--r--   1 root root   395 Jul  4 11:45 .bashrc
    -rw-r--r--   1 root root 68495 Jun 25 08:53 install.log
    -rw-r--r--   1 root root  5976 Jun 25 08:53 install.log.syslog
    drwx------   2 root root  4096 Jul  4 16:03 .ssh
    -rw-------   1 root root 12613 Jul 16 23:40 .viminfo
    # 這個時候您會看到以 . 為開頭的幾個檔案,以及目錄檔 ./../.ssh 等等,
    # 不過,目錄檔都是以深藍色顯示,有點不容易看清楚就是了。
    
    範例二:承上題,不顯示顏色,但在檔名末顯示出該檔名代表的類型(type)
    [root@linux ~]# ls -alF --color=never  ~
    total 252
    drwxr-x---   9 root root  4096 Jul 16 23:40 ./
    drwxr-xr-x  24 root root  4096 Jul 16 23:45 ../
    -rw-------   1 root root  1491 Jun 25 08:53 anaconda-ks.cfg
    -rw-------   1 root root 12543 Jul 18 01:23 .bash_history
    -rw-r--r--   1 root root    24 Dec  4  2004 .bash_logout
    -rw-r--r--   1 root root   191 Dec  4  2004 .bash_profile
    -rw-r--r--   1 root root   395 Jul  4 11:45 .bashrc
    -rw-r--r--   1 root root 68495 Jun 25 08:53 install.log
    -rw-r--r--   1 root root  5976 Jun 25 08:53 install.log.syslog
    drwx------   2 root root  4096 Jul  4 16:03 .ssh/
    -rw-------   1 root root 12613 Jul 16 23:40 .viminfo
    # 注意看到顯示結果的第一行,嘿嘿∼知道為何我們會下達類似 ./command 
    # 之類的指令了吧?因為 ./ 代表的是『目前目錄下』的意思啊!至於什麼是 FIFO/Socket ?
    # 請參考前一章節的介紹啊!
    
    範例三:完整的呈現檔案的修改時間 *(modification time)
    [root@linux ~]# ls -al --full-time  ~
    total 252
    drwxr-x---   9 root root  4096 2005-07-16 23:40:13.000000000 +0800 .
    drwxr-xr-x  24 root root  4096 2005-07-16 23:45:05.000000000 +0800 ..
    -rw-------   1 root root  1491 2005-06-25 08:53:37.000000000 +0800 anaconda-ks.cfg
    -rw-------   1 root root 12543 2005-07-18 01:23:33.000000000 +0800 .bash_history
    -rw-r--r--   1 root root    24 2004-12-04 05:44:13.000000000 +0800 .bash_logout
    -rw-r--r--   1 root root   191 2004-12-04 05:44:13.000000000 +0800 .bash_profile
    -rw-r--r--   1 root root   395 2005-07-04 11:45:16.000000000 +0800 .bashrc
    -rw-r--r--   1 root root 68495 2005-06-25 08:53:34.000000000 +0800 install.log
    -rw-r--r--   1 root root  5976 2005-06-25 08:53:28.000000000 +0800 install.log.syslog
    drwx------   2 root root  4096 2005-07-04 16:03:24.000000000 +0800 .ssh
    -rw-------   1 root root 12613 2005-07-16 23:40:13.000000000 +0800 .viminfo
    # 請仔細看,上面的『時間』欄位變了喔!變成較為完整的格式。
    # 一般來說, ls -al 僅列出目前短格式的時間,有時不會列出年份,
    # 藉由 --full-time 可以查閱到比較正確的完整時間格式啊!
    
    其實 ls 的用法還有很多,包括查閱檔案所在 i-node 的 ls -i 參數,以及用來進行檔案排序的 -S 參數,還有用來查閱不同時間的動作的 --time=atime 等參數。而這些參數的存在都是因為 Linux 檔案系統記錄了很多有用的資訊的緣故。那麼 Linux 的檔案系統中,這些與權限、屬性有關的資料放在哪裡呢? 放在 i-node 裡面。關於這部分,我們會在下個章節繼續跟您作比較深入的介紹啊!

    無論如何, ls 最常被使用到的功能還是那個 -l 的參數,為此,很多 distribution 在預設的情況中, 已經將 ll (L 的小寫) 設定成為 ls -l 的意思了!其實,那個功能是 Bash shell 的 alias 功能呢∼ 也就是說,我們直接輸入 ll 就等於是輸入 ls -l 是一樣的∼關於這部分,我們會在第三章 bash shell 時再次的強調滴∼


    複製、移動與刪除: cp, rm, mv
    要複製檔案,請使用 cp (copy) 這個指令即可∼不過, cp 這個指令的用途可多了∼ 除了單純的複製之外,還可以建立連結檔 (就是捷徑囉),比對兩檔案的新舊而予以更新, 以及複製整個目錄等等的功能呢!至於移動目錄與檔案,則使用 mv (move), 這個指令也可以直接拿來作更名 (rename) 的動作喔!至於移除嗎?那就是 rm (remove) 這個指令囉∼底下我們就來瞧一瞧先∼


  • cp (複製檔案或目錄)
  • [root@linux ~]# cp [-adfilprsu] 來源檔(source) 目的檔(destination)
    [root@linux ~]# cp [options] source1 source2 source3 .... directory
    參數:
    -a  :相當於 -pdr 的意思;
    -d  :若來源檔為連結檔的屬性(link file),則複製連結檔屬性而非檔案本身;
    -f  :為強制 (force) 的意思,若有重複或其他疑問時,不會詢問使用者,而強制複製;
    -i  :若目的檔(destination)已經存在時,在覆蓋時會先詢問是否真的動作!
    -l  :進行硬式連結 (hard link) 的連結檔建立,而非複製檔案本身;
    -p  :連同檔案的屬性一起複製過去,而非使用預設屬性;
    -r  :遞迴持續複製,用於目錄的複製行為;
    -s  :複製成為符號連結檔 (symbolic link),亦即『捷徑』檔案;
    -u  :若 destination 比 source 舊才更新 destination !
    最後需要注意的,如果來源檔有兩個以上,則最後一個目的檔一定要是『目錄』才行!
    範例:
    範例一:將家目錄下的 .bashrc 複製到 /tmp 下,並更名為 bashrc
    [root@linux ~]# cd /tmp
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# cp -i ~/.bashrc bashrc
    cp: overwrite `basrhc'? n
    # 重複作兩次動作,由於 /tmp 底下已經存在 bashrc 了,加上 -i 參數,
    # 則在覆蓋前會詢問使用者是否確定!可以按下 n 或者 y 呢!
    # 但是,反過來說,如果不想要詢問時,則加上 -f 這個參數來強制直接覆蓋!
    
    範例二:將 /var/log/wtmp 複製到 /tmp 底下
    [root@linux tmp]# cp /var/log/wtmp . <==想要複製到目前的目錄,最後的 . 不要忘
    [root@linux tmp]# ls -l /var/log/wtmp wtmp
    -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
    -rw-r--r--  1 root root 71808 Jul 18 21:58 wtmp
    # 注意到了嗎?!在不加任何參數的情況下,檔案的所屬者會改變,連權限也跟著改變了∼
    # 這是個很重要的特性!要注意喔!還有,連檔案建立的時間也不一樣了!
    # 如果您想要將檔案的所有特性都一起複製過來,可以加上 -a 喔!
    [root@linux tmp]# cp -a /var/log/wtmp wtmp_2
    [root@linux tmp]# ls -l /var/log/wtmp wtmp_2
    -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
    -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 wtmp_2
    # 瞭了吧!整個資料特性完全一模一樣ㄟ!真是不賴∼這就是 -a 的特性!
    
    範例三:複製 /etc/ 這個目錄下的所有內容到 /tmp 底下
    [root@linux tmp]# cp /etc/ /tmp
    cp: omitting directory `/etc'   <== 如果是目錄,不能直接複製,要加上 -r 的參數
    [root@linux tmp]# cp -r /etc/ /tmp
    # 還是要再次的強調喔! -r 是可以複製目錄,但是,檔案與目錄的權限會被改變∼
    # 所以,也可以利用 cp -a /etc /tmp 來下達指令喔!
    
    範例四:將範例一複製的 bashrc 建立一個連結檔 (symbolic link)
    [root@linux tmp]# ls -l bashrc
    -rw-r--r--  1 root root 395 Jul 18 22:08 bashrc
    [root@linux tmp]# cp -s bashrc bashrc_slink
    [root@linux tmp]# cp -l bashrc bashrc_hlink
    [root@linux tmp]# ls -l bashrc*
    -rw-r--r--  2 root root 395 Jul 18 22:08 bashrc
    -rw-r--r--  2 root root 395 Jul 18 22:08 bashrc_hlink
    lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
    # 那個 bashrc_slink 是由 -s 的參數造成的,建立的是一個『捷徑』,
    # 所以您會看到在檔案的最右邊,會顯示這個檔案是『連結』到哪裡去的!
    # 至於那個 bashrc_hlink 有趣了!建立了這個檔案之後, bashrc 與 bashrc_hlink 
    # 所有的參數都一樣,只是,第二欄的 link 數改變成為 2 了∼而不是原本的 1 喔!
    # 這兩種連結的方式的異同,我們會在下一章裡面進行介紹的!
    
    範例五:若 ~/.bashrc 比 /tmp/bashrc 新才複製過來
    [root@linux tmp]# cp -u ~/.bashrc /tmp/bashrc
    # 這個 -u 的特性,是在目標檔案與來源檔案有差異時,才會複製的。
    # 所以,比較常被用於『備份』的工作當中喔! ^_^
    
    範例六:將範例四造成的 bashrc_slink 複製成為 bashrc_slink_2
    [root@linux tmp]# cp bashrc_slink bashrc_slink_2
    [root@linux tmp]# ls -l bashrc_slink*
    lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
    -rw-r--r--  1 root root 395 Jul 18 22:48 bashrc_slink_2
    # 這個例子也是很有趣喔!原本複製的是連結檔,但是卻將連結檔的實際檔案複製過來了
    # 也就是說,如果沒有加上任何參數時,複製的是原始檔案,而非連結檔的屬性!
    # 若要複製連結檔的屬性,就得要使用 -d 或者 -a 的參數了!
    
    範例七:將家目錄的 .bashrc 及 .bash_history 複製到 /tmp 底下
    [root@linux tmp]# cp ~/.bashrc ~/.bash_history /tmp
    # 可以將多個資料一次複製到同一個目錄去!
    
    這個 cp 的功能很多,而由於我們常常在進行一些資料的複製,所以也會常常用到這個指令的。 一般來說,我們如果去複製別人的資料 (當然,該檔案您必須要有 read 的權限才行啊! ^_^) 時, 總是希望複製到的資料最後是我們自己的,所以,在預設的條件中, cp 的來源檔與目的檔的權限是不同的,目的檔的擁有者通常會是指令操作者本身。舉例來說, 上面的範例二中,由於我是 root 的身份,因此複製過來的檔案擁有者與群組就改變成為 root 所有了! 這樣說,可以明白嗎?! ^_^

    由於具有這個特性,因此,當我們在進行備份的時候,某些需要特別注意的特殊權限檔案, 例如密碼檔 (/etc/shadow) 以及一些設定檔,就不能直接以 cp 來複製,而必須要加上 -a 或者是 -p 等等可以完整複製檔案權限的參數才行!另外,如果您想要複製檔案給其他的使用者, 也必須要注意到檔案的權限(包含讀、寫、執行以及檔案擁有者等等), 否則,其他人還是無法針對您給予的檔案進行修訂的動作喔!注意注意!

    至於上面的範例當中,第四個範例是最有趣的,使用 -l 及 -s 都會建立所謂的連結檔 (link file), 但是這兩種連結檔確有不一樣的展現情況。這是怎麼一回事啊? 那個 -l 就是所謂的 hard link ,至於 -s 則是 symbolic link ,鳥哥這裡先不介紹, 因為這個涉及 i-node 的相關知識,我們還沒有介紹到,下一章再來討論這個 link 的問題喔! 總之,由於 cp 有種種的檔案屬性與權限的特性,所以,在複製時,您必須要清楚的瞭解到:
    • 是否需要完整的保留來源檔案的資訊?
    • 來源檔案是否為連結檔 (symbolic link file)?
    • 來源檔是否為特殊的檔案,例如 FIFO, socket 等?
    • 來源檔是否為目錄?

  • rm (移除檔案或目錄)
  • [root@linux ~]# rm [-fir] 檔案或目錄
    參數:
    -f  :就是 force 的意思,強制移除;
    -i  :互動模式,在刪除前會詢問使用者是否動作
    -r  :遞迴刪除啊!最常用在目錄的刪除了
    範例:
    範例一:建立一檔案後予以刪除
    [root@linux ~]# cd /tmp
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# rm -i bashrc
    rm: remove regular file `bashrc'? y
    # 如果加上 -i 的參數就會主動詢問喔!那麼如果不要詢問呢?就加 -f 參數啊!
    
    範例二:刪除一個不為空的目錄
    [root@linux tmp]# mkdir test
    [root@linux tmp]# cp ~/.bashrc test/ <== 將檔案複製到此目錄去,就不是空的目錄了
    [root@linux tmp]# rmdir test
    rmdir: `test': Directory not empty <== 刪不掉啊!因為這不是空的目錄!
    [root@linux tmp]# rm -rf test
    
    範例三:刪除一個帶有 - 開頭的檔案
    [root@linux tmp]# ls *aa*
    -rw-r--r--  1 root  root      0 Aug 22 10:52 -aaa-
    [root@linux tmp]# rm -aaa-
    rm: invalid option -- a
    Try `rm --help' for more information.  <== 因為 "-" 是參數嘛!
    [root@linux tmp]# rm ./-aaa-
    
    這是移除的指令( remove ),相當於 dos 下的 del 指令!這裡要注意的是,通常在 Linux 系統下,為了怕檔案被誤殺,所以很多 distributions 都已經預設有 -i 這個參數, -i 是指每個檔案被殺掉之前都會讓使用者確認一次,以預防誤殺檔案!而如果要連目錄下的東西都一起殺掉的話, 例如子目錄裡面還有子目錄時,那就要使用 -rf 這個參數了!不過,使用『 rm -rf 』這個指令之前,請千萬注意了,因為,該目錄或檔案『肯定』會被 root 殺掉!因為系統不會再次詢問你是否要砍掉呦!所以那是個超級嚴重的指令下達呦! 得特別注意!不過,如果你確定該目錄不要了,那麼使用 rm -rf 來循環殺掉是不錯的方式!

    另外,範例三也是很有趣的例子,我們在之前就談過,檔名最好不要使用 "-" 號開頭, 因為 "-" 後面接的是參數,因此,單純的使用『 rm -aaa- 』系統的指令就會誤判啦! 那如果使用後面會談到的正規表示法時,還是會出問題的!所以,只能用避過首位字元是 "-" 的方法啦! 就是加上本目錄『 ./ 』即可!如果 man rm 的話,其實還有一種方法,那就是『 rm -- -aaa- 』也可以啊!


  • mv (移動檔案與目錄,或更名)
  • [root@linux ~]# mv [-fiu] source destination
    [root@linux ~]# mv [options] source1 source2 source3 .... directory
    參數:
    -f  :force 強制的意思,強制直接移動而不詢問;
    -i  :若目標檔案 (destination) 已經存在時,就會詢問是否覆蓋!
    -u  :若目標檔案已經存在,且 source 比較新,才會更新 (update)
    範例:
    範例一:複製一檔案,建立一目錄,將檔案移動到目錄中
    [root@linux ~]# cd /tmp
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# mkdir mvtest
    [root@linux tmp]# mv bashrc mvtest
    # 將某個檔案移動到某個目錄去,就是這樣做!
    
    範例二:將剛剛的目錄名稱更名為 mvtest2
    [root@linux tmp]# mv mvtest mvtest2 <== 這樣就更名了!簡單∼
    # 其實在 Linux 底下還有個有趣的指令,名稱為 rename ,
    # 該指令則專職進行檔案的更名呢!用途也是不少∼可以參閱 man rename 喔!
    
    範例三:再建立兩個檔案,再全部移動到 /tmp/mvtest2 當中
    [root@linux tmp]# cp ~/.bashrc bashrc1
    [root@linux tmp]# cp ~/.bashrc bashrc2
    [root@linux tmp]# mv bashrc1 bashrc2 mvtest2
    # 注意到這邊,如果有多個來源檔案或目錄,則最後一個目標檔一定是『目錄!』
    # 意思是說,將所有的資料移動到該目錄的意思!
    
    這是搬移 (move) 的意思!當你要移動檔案或目錄的時後,呵呵!這個指令就很重要啦! 同樣的,你也可以使用 -u ( update )來測試新舊檔案,看看是否需要搬移囉! 另外一個用途就是『變更檔名!』,我們可以很輕易的使用 mv 來變更一個檔案的檔名呢!不過,在 Linux 才有的指令當中,有個 rename , 可以用來更改大量檔案的檔名,您可以利用 man rename 來查閱一下,也是挺有趣的指令喔!

    取得路徑的檔案名稱與目錄名稱
    我們前面介紹的完整檔名 (包含目錄名稱與檔案名稱) 當中提到,完整檔名最長可以到達 4096 個字元。 那麼您怎麼知道那個是檔名?那個是目錄名?嘿嘿!就是利用斜線 (/) 來分辨啊! 其實,取得檔名或者是目錄名稱,一般的用途應該是在寫程式的時候,用來判斷之用的啦∼ 所以,這部分的指令可以用在第三篇內的 shell scripts 裡頭喔! 底下我們簡單的以幾個範例來談一談 basename 與 dirname 的用途!
    [root@linux ~]# basename /etc/sysconfig/network
    network  <== 很簡單!就取得最後的檔名∼
    [root@linux ~]# dirname /etc/sysconfig/network
    /etc/sysconfig  <== 取得的變成目錄名了!
    
    很簡單的應用吧!

    檔案內容查閱:
    剛剛我們提到的都只是在於顯示檔案的屬性與權限,或者是移動與複製一個檔案或目錄而已, 那麼如果我們要查閱一個檔案的內容時,該如何是好呢?!這裡有相當多有趣的指令可以來分享一下: 最常使用的顯示檔案內容的指令可以說是 cat 與 more 及 less 了!此外,如果我們要查看一個很大型的檔案 ( 好幾百MB時 ),但是我們只需要後端的幾行字而已,那麼該如何是好?呵呵!用 tail 呀,此外, tac 這個指令也可以達到!好了,說說各個指令的用途吧!
    直接檢視檔案內容
    直接查閱一個檔案的內容可以使用 cat/tac/nl 這幾個指令啊!


  • cat (concatenate)
  • [root@linux ~]# cat [-AEnTv]
    參數:
    -A  :相當於 -vET 的整合參數,可列出一些特殊字符∼
    -E  :將結尾的斷行字元 $ 顯示出來;
    -n  :列印出行號;
    -T  :將 [tab] 按鍵以 ^I 顯示出來;
    -v  :列出一些看不出來的特殊字符
    範例:
    範例一:檢閱 /etc/issue 這個檔案的內容
    [root@linux ~]# cat /etc/issue
    Fedora Core release 4 (Stentz)
    Kernel \r on an \m
    
    範例二:承上題,順便列印出行號時!
    [root@linux ~]# cat -n /etc/issue
         1  Fedora Core release 4 (Stentz)
         2  Kernel \r on an \m
         3
    # 看到了吧!可以印出行號呢!這對於大檔案要找某個特定的行時,有點用處!
    
    範例三:將 /etc/xinetd.conf 的內容完整的顯示出來(包含特殊字元)
    [root@linux ~]# cat -A /etc/xinetd.conf
    #$
    # Simple configuration file for xinetd$
    #$
    # Some defaults, and include /etc/xinetd.d/$
    $
    defaults$
    {$
    ^Iinstances               = 60$
            log_type                = SYSLOG authpriv$
            log_on_success^I^I= HOST PID$
            log_on_failure^I^I= HOST$
    ^Icps^I^I^I= 25 30$
    }$
    $
    includedir /etc/xinetd.d$
    # 在一般的環境中,列印出來的結果在有 [tab] 與空白鍵,其實看不出來,
    # 那麼使用 cat -A 時,會將 [tab] 按鍵以 ^I 顯示,而斷行字元也會顯示出來∼
    # 最特殊的當然就是斷行字元了!這個段行字元在 Linux 與 Windows 是不一樣的。
    # 在 Linux 是以 $ 為斷行字元,而在 Windows 則是以 ^M$ 為斷行字元。
    # 這部分我們會在 vi 軟體的介紹時,再次的說明到喔!
    
    嘿嘿! Linux 裡面有『貓』?!喔!不是的, cat 是 Concatenate (連續)的簡寫, 主要的功能是將一個檔案的內容連續的印出在螢幕上面!例如上面的例子中,我們將 /etc/issue 印出來!如果加上 -n 的話,則每一行前面還會加上行號呦!鳥哥個人是比較少用 cat 啦!畢竟當你的檔案內容的行數超過 40 行以上,嘿嘿!根本來不及看!所以,配合等一下要介紹的 more 或者是 less 來執行比較好!此外,如果是一般的 DOS 檔案時,就需要特別留意一些奇奇怪怪的符號了, 例如斷行與 [tab] 等,要顯示出來,就得加入 -A 之類的參數了!


  • tac (反向列示)
  • [root@linux ~]# tac /etc/issue
    
    Kernel \r on an \m
    Fedora Core release 4 (Stentz)
    # 嘿嘿!與剛剛上面的範例一比較,是由最後一行先顯示喔!
    
    tac 這個好玩了!怎麼說呢?詳細的看一下, cat 與 tac ,有沒有發現呀!對啦! tac 剛好是將 cat 反寫過來,所以他的功能就跟 cat 相反啦, cat 是由『第一行到最後一行連續顯示在螢幕上』,而 tac 則是『 由最後一行到第一行反向在螢幕上顯示出來 』,很好玩吧!


  • nl (添加行號列印)
  • [root@linux ~]# nl [-bnw] 檔案
    參數:
    -b  :指定行號指定的方式,主要有兩種:
          -b a :表示不論是否為空行,也同樣列出行號;
          -b t :如果有空行,空的那一行不要列出行號;
    -n  :列出行號表示的方法,主要有三種:
          -n ln :行號在螢幕的最左方顯示;
          -n rn :行號在自己欄位的最右方顯示,且不加 0 ;
          -n rz :行號在自己欄位的最右方顯示,且加 0 ;
    -w  :行號欄位的佔用的位元數。
    範例:
    範例一:列出 /etc/issue 的內容
    [root@linux ~]# nl /etc/issue
         1  Fedora Core release 4 (Stentz)
         2  Kernel \r on an \m
    
    # 注意看,這個檔案其實有三行,第三行為空白(沒有任何字元),
    # 因為他是空白行,所以 nl 不會加上行號喔!如果確定要加上行號,可以這樣做:
    
    [root@linux ~]# nl -b a /etc/issue
         1  Fedora Core release 4 (Stentz)
         2  Kernel \r on an \m
         3
    # 呵呵!行號加上來囉∼那麼如果要讓行號前面自動補上 0 呢?可這樣
    
    [root@linux ~]# nl -b a -n rz /etc/issue
    000001  Fedora Core release 4 (Stentz)
    000002  Kernel \r on an \m
    000003
    # 嘿嘿!自動在自己欄位的地方補上 0 了∼預設欄位是六位數,如果想要改成 3 位數?
    
    [root@linux ~]# nl -b a -n rz -w 3 /etc/issue
    001     Fedora Core release 4 (Stentz)
    002     Kernel \r on an \m
    003
    # 變成僅有 3 位數囉∼
    
    nl 可以將輸出的檔案內容自動的加上行號!其結果與 cat -n 有點不太一樣, nl 可以將行號做比較多的顯示設計,包括位數與是否自動補齊 0 等等的功能呢∼

    可翻頁檢視
    前面提到的 nl 與 cat, tac 等等,都是一次性的將資料顯示到螢幕上面,那有沒有可以進行一頁一頁翻動的指令啊? 讓我們可以一頁一頁的觀察,才不會前面的看不到啊∼呵呵!有的!那就是 more 與 less 囉∼


  • more (一頁一頁翻動)
  • [root@linux ~]# more /etc/man.config
    #
    # Generated automatically from man.conf.in by the
    # configure script.
    #
    # man.conf from man-1.5p
    #
    .......中間省略.......
    --More--(28%) <== 重點在這一行喔!
    
    仔細的給他看到上面的範例,如果 more 後面接的檔案長度大於螢幕輸出的行數時, 就會出現類似上面的圖示。重點在最後一行,最後一行會顯示出目前顯示的百分比, 而且還可以在最後一行輸入一些有用的指令喔!在 more 這個程式的運作過程中,你有幾個按鍵可以按的:
    • 空白鍵 (space):代表向下翻一頁;
    • Enter         :代表向下翻『一行』;
    • /字串         :代表在這個顯示的內容當中,向下搜尋『字串』;
    • :f            :立刻顯示出檔名以及目前顯示的行數;
    • q             :代表立刻離開 more ,不再顯示該檔案內容。
    要離開 more 這個指令的顯示工作,可以按下 q 就能夠離開了。而要向下翻頁,就使用空白鍵即可。 比較有用的是搜尋字串的功能,舉例來說,我們使用『 more /etc/man.config 』來觀察該檔案, 若想要在該檔案內搜尋 MANPATH 這個字串時,可以這樣做:
    [root@linux ~]# more /etc/man.config
    #
    # Generated automatically from man.conf.in by the
    # configure script.
    #
    # man.conf from man-1.5p
    #
    .......中間省略.......
    /MANPATH   <== 輸入了 / 之後,游標就會自動跑到最底下一行等待輸入!
    
    如同上面的說明,輸入了 / 之後,游標就會跑到最底下一行,並且等待您的輸入, 您輸入了字串之後,嘿嘿! more 就會開始向下搜尋該字串囉∼而重複搜尋同一個字串, 可以直接按下 n 即可啊!最後,不想要看了,就按下 q 即可離開 more 啦!


  • less (一頁一頁翻動)
  • [root@linux ~]# less /etc/man.config
    #
    # Generated automatically from man.conf.in by the
    # configure script.
    #
    # man.conf from man-1.5p
    ......中間省略........
    :   <== 這裡可以等待您輸入指令!
    
    less 的用法比起 more 又更加的有彈性,怎麼說呢?在 more 的時候,我們並沒有辦法向前面翻, 只能往後面看,但若使用了 less 時,呵呵!就可以使用 [pageup] [pagedown] 等按鍵的功能來往前往後翻看文件,您瞧,是不是更容易使用來觀看一個檔案的內容了呢!?

    除此之外,在 less 裡頭可以擁有更多的『搜尋』功能喔!不止可以向下搜尋,也可以向上搜尋∼ 實在是很不錯用∼基本上,可以輸入的指令有:
    • 空白鍵    :向下翻動一頁;
    • [pagedown]:向下翻動一頁;
    • [pageup]  :向上翻動一頁;
    • /字串     :向下搜尋『字串』的功能;
    • ?字串     :向上搜尋『字串』的功能;
    • n         :重複前一個搜尋 (與 / 或 ? 有關!)
    • N         :反向的重複前一個搜尋 (與 / 或 ? 有關!)
    • q         :離開 less 這個程式;
    查閱檔案內容還可以進行搜尋的動作∼瞧∼ less 是否很不錯用啊! 其實 less 還有很多的功能喔!詳細的使用方式請使用 man less 查詢一下啊! ^_^

    資料擷取
    我們可以將輸出的資料作一個最簡單的擷取,那就是取出前面 (head) 與取出後面 (tail) 文字的功能。 不過,要注意的是, head 與 tail 都是以『行』為單位來進行資料擷取的喔!


  • head (取出前面幾行)
  • [root@linux ~]# head [-n number] 檔案 
    參數:
    -n  :後面接數字,代表顯示幾行的意思
    範例:
    [root@linux ~]# head /etc/man.config
    # 預設的情況中,顯示前面十行!若要顯示前 20 行,就得要這樣:
    
    [root@linux ~]# head -n 20 /etc/man.config
    
    head 的英文意思就是『頭』啦,那麼這個東西的用法自然就是顯示出一個檔案的前幾行囉! 沒錯!就是這樣!若沒有加上 -n 這個參數時,預設只顯示十行,若只要一行呢?那就加入『 head -n 1 filename 』即可!


  • tail (取出後面幾行)
  • [root@linux ~]# tail [-n number] 檔案 
    參數:
    -n  :後面接數字,代表顯示幾行的意思
    範例:
    [root@linux ~]# tail /etc/man.config
    # 預設的情況中,顯示最後的十行!若要顯示最後的 20 行,就得要這樣:
    
    [root@linux ~]# tail -n 20 /etc/man.config
    
    那麼有 head 自然就有 tail ( 尾巴 ) 囉!沒錯!這個 tail 的用法跟 head 的用法差不多類似,只是顯示的是後面幾行就是了!預設也是顯示十行,若要顯示非十行,就加 -n number 的參數!
    例題一:假如我想要顯示 ~/.bashrc 的第 11 到第 20 行呢?
    答:
      這個應該不算難,想一想,在第 11 到第 20 行,那麼我取前 20 行,再取後十行,所以結果就是:『 head –n 20 ~/.bashrc | tail –n 10 』,這樣就可以得到第 11 到第 20 行之間的內容了! 但是裡面涉及到管線命令,需要在第三篇的時候才講的到!


    非純文字檔: od
    我們上面提到的,都是在查閱純文字檔 (ASCII 格式的檔案) 的內容。 那麼萬一我們想要查閱非文字檔,舉例來說,例如 /usr/bin/passwd 這個執行檔的內容時, 又該如何去讀出資訊呢?事實上,由於執行檔通常是 binary file ,使用上頭提到的指令來讀取他的內容時, 確實會產生類似亂碼的資料啊!那怎麼辦?沒關係,我們可以利用 od 這個指令來讀取喔!
    [root@linux ~]# od [-t TYPE] 檔案
    參數:
    -t  :後面可以接各種『類型 (TYPE)』的輸出,例如:
          a       :利用預設的字元來輸出;
          c       :使用 ASCII 字元來輸出
          d[size] :利用十進位(decimal)來輸出資料,每個整數佔用 size bytes ;
          f[size] :利用浮點數值(floating)來輸出資料,每個數佔用 size bytes ;
          o[size] :利用八進位(octal)來輸出資料,每個整數佔用 size bytes ;
          x[size] :利用十六進位(hexadecimal)來輸出資料,每個整數佔用 size bytes ;
    範例:
    [root@linux ~]# od -t c /usr/bin/passwd
    0000000 177   E   L   F 001 001 001  \0  \0  \0  \0  \0  \0  \0  \0  \0
    0000020 002  \0 003  \0 001  \0  \0  \0 260 225 004  \b   4  \0  \0  \0
    0000040 020   E  \0  \0  \0  \0  \0  \0   4  \0      \0  \a  \0   (  \0
    0000060 035  \0 034  \0 006  \0  \0  \0   4  \0  \0  \0   4 200 004  \b
    0000100   4 200 004  \b 340  \0  \0  \0 340  \0  \0  \0 005  \0  \0  \0
    .....中間省略.......
    
    利用這個指令,可以將 data file 或者是 binary file 的內容資料給他讀出來喔! 雖然讀出的來數值預設是使用非文字檔,亦即是 16 進位的數值來顯示的, 不過,我們還是可以透過 -t c 的參數來將資料內的字元以 ASCII 類型的字元來顯示, 雖然對於一般使用者來說,這個指令的用處可能不大,但是對於工程師來說, 這個指令可以將 binary file 的內容作一個大致的輸出,他們可以看得出東西的啦∼ ^_^


    修改檔案時間與建置新檔: touch
    我們在 ls 這個指令的介紹時,有稍微提到每個檔案在 linux 底下都會記錄三個主要的變動時間, 咦!那麼三個時間是哪三個呢? 這是個挺有趣的現象,舉例來說,我們來看一看您自己的 /etc/man.config 這個檔案的時間吧!
    [root@linux ~]# ls -l /etc/man.config
    -rw-r--r--  1 root root 4506 Apr  8 19:11 /etc/man.config
    [root@linux ~]# ls -l --time=atime /etc/man.config
    -rw-r--r--  1 root root 4506 Jul 19 17:53 /etc/man.config
    [root@linux ~]# ls -l --time=ctime /etc/man.config
    -rw-r--r--  1 root root 4506 Jun 25 08:28 /etc/man.config
    
    看到了嗎?在預設的情況下, ls 顯示出來的是該檔案的 mtime ,也就是這個檔案的內容上次被更動的時間。 至於我的系統是在 6/25 的時候安裝的,因此,這個檔案被產生但是狀態被更動的時間就回溯到那個時間點了! 而還記得剛剛我們使用的範例當中,有使用到這個檔案啊,所以啊,他的 atime 就會變成剛剛使用的時間了!

    檔案的時間是很重要的,因為,如果檔案的時間誤判的話,可能會造成某些程式無法順利的運作∼ OK!那麼萬一我發現了一個檔案來自未來(嘿嘿!不要懷疑!很多時候會有這個問題的!這個我們在安裝的時候, 提到的 GMT 時間就是那個意思啦∼),那該如何讓該檔案的時間變成『現在』的時刻呢? 很簡單啊!就用『touch』這個指令即可!
    [root@linux ~]# touch [-acdmt] 檔案
    參數:
    -a  :僅修訂 access time;
    -c  :僅修改時間,而不建立檔案;
    -d  :後面可以接日期,也可以使用 --date="日期或時間"
    -m  :僅修改 mtime ;
    -t  :後面可以接時間,格式為[YYMMDDhhmm]
    範例:
    
    範例一:新建一個空的檔案
    [root@linux ~]# cd /tmp
    [root@linux tmp]# touch testtouch
    [root@linux tmp]# ls -l testtouch
    -rw-r--r--  1 root root    0 Jul 19 20:49 testtouch
    # 注意到,這個檔案的大小是 0 呢!在預設的狀態下,如果 touch 後面有接檔案,
    # 則該檔案的三個時間 (atime/ctime/mtime) 都會更新為目前的時間。若該檔案不存在,
    # 則會主動的建立一個新的空的檔案喔!例如上面這個例子!
    
    範例二:將 ~/.bashrc 複製成為 bashrc,假設複製完全的屬性,檢查其日期
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
    -rwxr-xr-x  1 root root 395 Jul  4 11:45 bashrc  <==這是 mtime
    -rwxr-xr-x  1 root root 395 Jul 19 20:44 bashrc  <==這是 atime
    -rwxr-xr-x  1 root root 395 Jul 19 20:53 bashrc  <==這是 ctime
    # 在這個案例當中,我們使用了 ; 這個指令分隔符號,他的用法我們會在 Bash shell 中提到。
    # 此外, ll 是 ls -l 的命令別名,這個我們也會在 bash shell 當中再次提及,
    # 您目前可以簡單的想成, ll 就是 ls -l 的簡寫即可!至於 ; 則是同時下達兩個指令,
    # 且讓兩個指令『依序』執行的意思。上面的結果當中我們可以看到,該檔案變更的日期
    # Jul 4 11:45,但是 atime 與 ctime 不一樣囉∼
    
    範例三:修改案例二的 bashrc 檔案,將日期調整為兩天前
    [root@linux tmp]# touch -d "2 days ago" bashrc
    [root@linux tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
    -rwxr-xr-x  1 root root 395 Jul 17 21:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 17 21:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 19 21:02 bashrc
    # 跟上個範例比較看看,本來是 19 日的變成了 17 日了 (atime/mtime)∼
    # 不過, ctime 並沒有跟著改變喔!
    
    範例四:將上個範例的 bashrc 日期改為 2005/07/15 2:02
    [root@linux tmp]# touch -t 0507150202 bashrc
    [root@linux tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
    -rwxr-xr-x  1 root root 395 Jul 15 02:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 15 02:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 19 21:05 bashrc
    # 注意看看,日期在 atime 與 mtime 都改變了,但是 ctime 則是記錄目前的時間!
    
    透過 touch 這個指令,我們可以輕易的修訂檔案的日期與時間。並且,也可以建立一個空的檔案喔! 不過,要注意的是,即使我們複製一個檔案時,複製所有的屬性,但也沒有辦法複製 ctime 這個屬性的。 ctime 可以記錄這個檔案最近的狀態 (status) 被改變的時間。無論如何,還是要告知大家, 我們平時看的檔案屬性中,比較重要的還是屬於那個 mtime 啊!我們關心的常常是這個檔案的『內容』 是什麼時候被更動的說∼瞭乎?

    無論如何, touch 這個指令最常被使用的情況是:

    檔案與目錄的預設權限與隱藏權限
    由前一章的 Linux 檔案屬性 的內容我們可以知道一個檔案有若干個屬性,包括 ( r, w, x ) 等基本屬性,及是否為目錄 (d) 與檔案 (-) 或者是連結檔 (l) 等等的屬性!那麼要修改屬性的方法在前面也約略提過了,這裡再加強補充一下! 此外,由於 Linux 還可以設定其他的系統安全屬性,使用 chattr 來設定,而以 lsattr 來查看,最重要的屬性就是可以設定其不可修改的特性!讓連檔案的擁有者都不能進行修改! 這個屬性可是相當重要的,尤其是在安全機制上面 ( security )!

    首先,先來複習一下上一章談到的權限概念,將底下的例題看一看先∼

    例題二:你的系統有個一般身份使用者 dmtsai,他的群組為 users,他的家目錄在 /home/dmtsai, 你想將你的 ~/.bashrc 複製給他(假設你是 root),可以怎麼作?
    答:
      cp ~/.bashrc ~dmtsai/bashrc
      chown dmtsai:users ~dmtsai/bashrc

    在上面這個範例當中,我為了怕覆蓋掉 dmtsai 自己的 ~dmtsai/.bashrc ,所以將檔名更名了∼ 而複製給他後,還要修正這個檔案的擁有者與群組才行喔!

    例題三:我想在 /tmp 底下建立一個目錄,這個目錄名稱為 chap2_2_ex1 ,並且,這個目錄擁有者為 dmtsai, 群組為 users ,此外,任何人都可以進入該目錄瀏覽檔案,不過除了 dmtsai 之外,其他人都不能修改該目錄下的檔案。
    答:
      因為除了 dmtsai 之外,其他人不能修改該目錄下的檔案,此外, dmtsai 可以修改, 所以整個目錄的權限應該是 drwxr-xr-x 才對!因此
      mkdir /tmp/chap2_2_ex1
      chown -R dmtsai:users /tmp/chap2_2_ex1
      chmod -R 755 /tmp/chap2_2_ex1

    在上面這個例題當中,如果您知道 755 那個分數是怎麼計算出來的,那麼您應該對於權限有一定程度的概念了。 如果您不知道 755 怎麼來的?那麼.....趕快回去前一章看看 chmod 那個指令的介紹部分啊!這部分很重要喔!您得要先清楚的瞭解到才行∼否則就進行不下去囉∼ 假設您對於權限都認識的差不多了,那麼底下我們就要來談一談, 『新增一個檔案或目錄時,預設的權限是什麼?』這個議題!


    檔案預設權限:umask
    OK!那麼現在我們知道如何建立或者是改變一個目錄或檔案的屬性了,不過, 您知道當你建立一個新的檔案或目錄時,他的預設屬性會是什麼嗎?呵呵!那就與 umask 這個玩意兒有關了!那麼 umask 是在搞什麼呢?基本上, umask 就是指定 『目前使用者在建立檔案或目錄時候的屬性預設值』, 那麼如何得知或設定 umask 呢?他的指定條件以底下的方式來指定:
    [root@linux ~]# umask
    0022
    [root@linux ~]# umask -S
    u=rwx,g=rx,o=rx
    
    查閱的方式有兩種,一種可以直接輸入 umask ,就可以看到數字型態的權限設定分數, 一種則是加入 -S (Symbolic) 這個參數,就會以符號類型的方式來顯示出權限了! 奇怪的是,怎麼 umask 會有四組數字啊?不是只有三組嗎?是沒錯啦∼ 第一組是特殊權限用的,我們先不要理他,所以先看後面三組即可。

    在預設權限的屬性上,目錄與檔案是不一樣的。由於檔案我們不希望他具有可執行的權力, 預設情況中,檔案是沒有可執行 (x) 權限的。因此: 那麼 umask 指定的是『該預設值需要減掉的權限!』因為 r、w、x 分別是 4、2、1 分,所以囉!也就是說,當要拿掉能寫的權限,就是輸入 2 分,而如果要拿掉能讀的權限,也就是 4 分,那麼要拿掉讀與寫的權限,也就是 6 分,而要拿掉執行與寫入的權限,也就是 3 分,這樣瞭解嗎?請問您, 5 分是什麼?呵呵! 就是讀與執行的權限啦!如果以上面的例子來說明的話,因為 umask 為 022 ,所以 user 並沒有被拿掉屬性,不過 group 與 others 的屬性被拿掉了 2 ( 也就是 w 這個屬性 ),那麼由於當使用者: 不相信嗎?我們就來測試看看吧!
    [root@linux ~]# umask
    0022
    [root@linux ~]# touch test1
    [root@linux ~]# mkdir test2
    [root@linux ~]# ll 
    -rw-r--r--  1 root root    0 Jul 20 00:36 test1
    drwxr-xr-x  2 root root 4096 Jul 20 00:36 test2
    
    呵呵!瞧見了吧?!確定屬性是沒有錯的。好了,假如我們想要讓與使用者同群組的人也可以存取檔案呢? 也就是說,假如 dmtsai 是 users 這個群組的人,而 dmtsai 作的檔案希望讓 users 同群組的人也可以存取, 這也是常常被用在團隊開發計畫時,常常會考慮到的權限問題。在這樣的情況下, 我們的 umask 自然不能取消 group 的 w 權限,也就是說,我們希望製作出來的檔案應該是 -rw-rw-r-- 的模樣,所以囉, umask 應該是要 002 才好 (僅拿掉 others 的 w 權限)。那麼如何設定 umask 呢? 簡單的很,直接在 umask 後面輸入 002 就好了!
    [root@linux ~]# umask 002
    [root@linux ~]# touch test3
    [root@linux ~]# mkdir test4
    [root@linux ~]# ll 
    -rw-rw-r--  1 root root    0 Jul 20 00:41 test3
    drwxrwxr-x  2 root root 4096 Jul 20 00:41 test4
    
    所以說,這個 umask 對於檔案與目錄的預設權限是很有關係的!這個概念可以用在任何伺服器上面, 尤其是未來在您架設檔案伺服器 (file server) ,舉例來說, SAMBA Server 或者是 FTP server 時, 都是很重要的觀念!這牽涉到您的使用者是否能夠將檔案進一步利用的問題喔!不要等閒視之!

    例題四:假設您的 umask 為 003 ,請問該 umask 情況下,建立的檔案與目錄權限為?
    答:
      umask 為 003 ,所以拿掉的屬性為 --------wx,因此:
      檔案: (-rw-rw-rw-) - (--------wx) = -rw-rw-r--
      目錄: (drwxrwxrwx) - (--------wx) = drwxrwxr--

    關於 umask 與權限的計算方式中,教科書喜歡使用二進位的方式來進行 AND 與 NOT 的計算, 不過,鳥哥還是比較喜歡使用符號方式來計算∼聯想上面比較容易一點∼ 但是,有的書籍或者是 BBS 上面的朋友,有的人喜歡使用檔案預設屬性 666 與目錄預設屬性 777 來與 umask 進行相減的計算∼這是不好的喔!以上面例題四的案例來看, 如果使用預設屬性相加減,則檔案變成:666-003=663,亦即是 -rw-rw--wx ,這可是完全不對的喔! 想想看,原本檔案就已經去除 x 的預設屬性了,怎麼可能突然間冒出來了? 所以,這個地方得要特別小心喔! 在預設的情況中, root 的 umask 會拿掉比較多的屬性,root 的 umask 預設是 022 , 這是基於安全的考量啦∼至於一般身份使用者,通常他們的 umask 為 002 ,亦即保留同群組的寫入權力! 其實,關於預設 umask 的設定可以參考 /etc/bashrc 這個檔案的內容,不過,不建議修改該檔案, 您可以參考 bash shell 提到的環境參數設定檔 (~/.bashrc) 的說明∼這部分我們在第三章的時候會提到!


    檔案隱藏屬性:
    什麼?檔案還有隱藏屬性?光是那九個權限就快要瘋掉了,竟然還有隱藏屬性,真是要命∼ 但是沒辦法,就是有檔案的隱藏屬性存在啊!不過,這些隱藏的屬性確實對於系統有很大的幫助的∼ 尤其是在系統安全 (Security) 上面,重要的緊呢!底下我們就來談一談如何設定與檢查這些隱藏的屬性吧!


  • chattr (設定檔案隱藏屬性)
  • [root@linux ~]# chattr [+-=][ASacdistu] 檔案或目錄名稱
    參數:
    +   :增加某一個特殊參數,其他原本存在參數則不動。
    -   :移除某一個特殊參數,其他原本存在參數則不動。
    =   :設定一定,且僅有後面接的參數
    
    A  :當設定了 A 這個屬性時,這個檔案(或目錄)的存取時間 atime (access) 
         將不可被修改,可避免例如手提式電腦容易有磁碟 I/O 錯誤的情況發生!
    S  :這個功能有點類似 sync 的功能!就是會將資料同步寫入磁碟當中!
         可以有效的避免資料流失!
    a  :當設定 a 之後,這個檔案將只能增加資料,而不能刪除,只有 root 
         才能設定這個屬性。 
    c  :這個屬性設定之後,將會自動的將此檔案『壓縮』,在讀取的時候將會自動解壓縮,
         但是在儲存的時候,將會先進行壓縮後再儲存(看來對於大檔案似乎蠻有用的!)
    d  :當dump(備份)程序被執行的時候,設定 d 屬性將可使該檔案(或目錄)不具有dump功能
    i  :這個 i 可就很厲害了!他可以讓一個檔案『不能被刪除、改名、設定連結也無法寫入
         或新增資料!』對於系統安全性有相當大的助益!
    j  :當使用 ext3 這個檔案系統格式時,設定 j 屬性將會使檔案在寫入時先記錄在 
         journal 中!但是當 filesystem 設定參數為 data=journalled 時,由於已經設定了
         日誌了,所以這個屬性無效!
    s  :當檔案設定了 s 參數時,他將會被完全的移除出這個硬碟空間。
    u  :與 s 相反的,當使用 u 來設定檔案時,則資料內容其實還存在磁碟中,
         可以使用來 undeletion.
    注意:這個屬性設定上面,比較常見的是 a 與 i 的設定值,而且很多設定值必須要身為
    root 才能夠設定的喔!
    範例:
    [root@linux ~]# cd /tmp
    [root@linux tmp]# touch attrtest
    [root@linux tmp]# chattr +i attrtest
    [root@linux tmp]# rm attrtest
    rm: remove write-protected regular empty file `attrtest'? y
    rm: cannot remove `attrtest': Operation not permitted
    # 看到了嗎?呼呼!連 root 也沒有辦法將這個檔案刪除呢!趕緊解除設定!
    [root@linux tmp]# chattr -i attrtest
    
    這這個指令是重要的,尤其是在系統的安全性上面!由於這些屬性是隱藏的性質,所以需要以 lsattr 才能看到該屬性呦!其中,個人認為最重要的當屬 +i 這個屬性了,因為他可以讓一個檔案無法被更動,對於需要強烈的系統安全的人來說, 真是相當的重要的!裡頭還有相當多的屬性是需要 root 才能設定的呢!此外,如果是 log file 這種的登錄檔,就更需要 +a 這個可以增加,但是不能修改舊有的資料與刪除的參數了! 怎樣?很棒吧!未來提到登錄檔的認知時,我們再來聊一聊如何設定他吧!


  • lsattr (顯示檔案隱藏屬性)
  • [root@linux ~]# lsattr [-aR] 檔案或目錄
    參數:
    -a :將隱藏檔的屬性也秀出來;
    -R :連同子目錄的資料也一併列出來! 
    範例:
    [root@linux tmp]# chattr +aij attrtest
    [root@linux tmp]# lsattr
    ----ia---j--- ./attrtest
    
    使用 chattr 設定後,可以利用 lsattr 來查閱隱藏的屬性。不過, 這兩個指令在使用上必須要特別小心,否則會造成很大的困擾。例如:某天你心情好,突然將 /etc/shadow 這個重要的密碼記錄檔案給他設定成為具有 i 的屬性,那麼過了若干天之後, 你突然要新增使用者,卻一直無法新增!別懷疑,趕快去將 i 的屬性拿掉吧!

    檔案特殊權限: SUID/SGID/Sticky Bit
    我們前面一直提到關於檔案的重要權限,那就是 rwx 這三個讀、寫、執行的權限。 但是,眼尖的朋友們一定注意到了一件事,那就是,怎麼我們的 /tmp 權限怪怪的? 還有,那個 /usr/bin/passwd 也怪怪的?怎麼回事啊?看看先:
    [root@linux ~]# ls -ld /tmp ; ls -l /usr/bin/passwd
    drwxrwxrwt  5 root root 4096 Jul 20 10:00 /tmp
    -r-s--x--x  1 root root 18840 Mar  7 18:06 /usr/bin/passwd
    
    不是只有 rwx 嗎?還有其他的特殊權限啊?啊.....頭又開始昏了∼ @_@ 呵呵,不要擔心啦,我們這裡先不談這兩個權限,只是先介紹一下而已。 因為要瞭解這幾個特殊的權限,必須要先具有帳號的 ID 概念,以及程式的程序 (process) 概念後, 才能夠進一步的瞭解這個特殊權限所代表的意義。

  • Set UID
  • 會製作出 s 與 t 的權限,是為了讓一般使用者在執行某些程式的時候, 能夠暫時的具有該程式擁有者的權限。 舉例來說好了,我們知道帳號與密碼的存放檔案其實是 /etc/passwd 與 /etc/shadow 。 而 /etc/shadow 這個檔案的權限是什麼?是『-r--------』。且他的擁有者是 root 喔!在這個權限中,僅有 root 可以『強制』儲存,其他人是連看都沒有辦法看的吶!

    但是偏偏鳥哥使用 dmtsai 這個一般身份使用者去更新自己的密碼時,使用的就是 /usr/bin/passwd 這個程式, 卻是可以更新自己的密碼的,也就是說, dmtsai 這個一般身份使用者可以存取 /etc/shadow 這個密碼檔! 但!怎麼可能?明明 /etc/shadow 就是沒有 dmtsai 可以存取的權限啊!呵呵∼這就是 s 這個權限的幫助啦! 當 s 這個權限在 user 的 x 時,也就是類似上表的 -r-s--x--x ,稱為 Set UID ,簡稱為 SUID , 這個 UID 代表的是 User 的 ID ,而 User 代表的則是這個程式 (/usr/bin/passwd) 的擁有者 (root 啊!)。 那麼由上面的定義中,我們知道了,當 dmtsai 這個使用者執行 /usr/bin/passwd 時,他就會『暫時』的得到檔案擁有人 root 的權限

    SUID 僅可用在『二進位制檔案(binary file)』上, SUID 因為是程式在執行的過程中擁有檔案擁有者的權限,因此,他僅可用於 binary file , 不能夠用在批次檔 (shell script) 上面的!這是因為 shell script 只是將很多的 binary 執行檔叫進來執行而已!所以 SUID 的權限部分,還是得要看 shell script 呼叫進來的程式的設定, 而不是 shell script 本身。當然,SUID 對於目錄也是無效的∼這點要特別留意。

  • Set GID
  • 進一步來說,如果 s 的權限是在 group 時,那麼就是 Set GID ,簡稱為 SGID。 SGID 可以用在兩個部分喔!
    • 檔案:如果 SGID 是設定在 binary file 上面,則不論使用者是誰,在執行該程式的時候, 他的有效群組 (effective group) 將會變成該程式的群組所有人 (group id)。

    • 目錄:如果 SGID 是設定在 A 目錄上面,則在該 A 目錄內所建立的檔案或目錄的 group ,將會是 此 A 目錄的 group !
    一般來說, SGID 應該是比較多用在特定的多人團隊的專案開發上, 在系統當中應該會比較少這個設定才對∼

  • Sticky Bit
  • 這個 Sticky Bit 目前只針對目錄有效,對於檔案已經沒有效果了。 SBit 對於目錄的作用是:『在具有 SBit 的目錄下,使用者若在該目錄下具有 w 及 x 的權限, 則當使用者在該目錄下建立檔案或目錄時,只有檔案擁有者與 root 才有權力刪除』。換句話說:當甲這個使用者於 A 目錄下是擁有 group 或者是 other 的項目,並且擁有 w 的權限, 這表示『甲使用者對該目錄內任何人建立的目錄或檔案均可進行 "刪除/更名/搬移" 等動作。』 不過,如果將 A 目錄加上了 Sticky bit 的權限項目時, 則甲只能夠針對自己建立的檔案或目錄進行刪除/更名/移動等動作。

    舉例來說,我們的 /tmp 本身的權限是『drwxrwxrwt』, 在這樣的權限內容下,任何人都可以在 /tmp 內新增、修改檔案,但僅有該檔案/目錄建立者與 root 能夠刪除自己的目錄或檔案。這個特性也是挺重要的啊!你可以這樣做個簡單的測試:
      1. 以 root 登入系統,並且進入 /tmp 當中;
      2. touch test,並且更改 test 權限成為 777 ;
      3. 以一般使用者登入,並進入 /tmp;
      4. 嘗試刪除 test 這個檔案!
    更多關於 SUID/SGID/Sticky Bit 的介紹,我們會在 程序與資源管理 中再次提及的,目前,您先有個簡單的基礎概念就好了!當然,也可以參考鳥園討論區的這一篇討論: http://phorum.vbird.org/viewtopic.php?t=20256

  • SUID/SGID/SBIT 權限設定
  • 前面介紹過 SUID 與 SGID 的功能,那麼如何開啟檔案使成為具有 SUID 與 SGID 的權限呢?! 這就需要剛剛的數字更改權限的方法了!現在你應該已經知道數字型態個更改權限方式為『三個數字』的組合, 那麼如果在這三個數字之前再加上一個數字的話,那最前的面數字就代表這幾個屬性了! ( 註:通常我們使用 chmod xyz filename 的方式來設定 filename 的屬性時,則是假設沒有 SUID, SGID 及 Sticky bit 啦! )
    • 4 為 SUID
    • 2 為 SGID
    • 1 為 Sticky bit
    假設要將一個檔案屬性改為『-rwsr-xr-x』時,由於 s 在使用者權限中,所以是 SUID ,因此, 在原先的 755 之前還要加上 4 ,也就是:『 chmod 4755 filename 』來設定!此外,還有大 S 與大 T 的產生喔!參考底下的範例啦!(注意:底下的範例只是練習而已, 所以鳥哥使用同一個檔案來設定,您必須瞭解 SUID 不是用在目錄上,而 SBIT 不是用在檔案上的喔!)
    [root@linux ~]# cd /tmp
    [root@linux tmp]# touch test
    [root@linux tmp]# chmod 4755 test; ls -l test
    -rwsr-xr-x  1 root root 0 Jul 20 11:27 test
    [root@linux tmp]# chmod 6755 test; ls -l test
    -rwsr-sr-x  1 root root 0 Jul 20 11:27 test
    [root@linux tmp]# chmod 1755 test; ls -l test
    -rwxr-xr-t  1 root root 0 Jul 20 11:27 test
    [root@linux tmp]# chmod 7666 test; ls -l test
    -rwSrwSrwT  1 root root 0 Jul 20 11:27 test
    # 這個例子就要特別小心啦!怎麼會出現大寫的 S 與 T 呢?不都是小寫的嗎?
    # 因為 s 與 t 都是取代 x 這個參數的,但是你有沒有發現阿,我們是下達 
    # 7666 喔!也就是說, user, group 以及 others 都沒有 x 這個可執行的標誌 
    # ( 因為 666 嘛! ),所以,這個 S, T 代表的就是『空的』啦!怎麼說? 
    # SUID 是表示『該檔案在執行的時候,具有檔案擁有者的權限』,但是檔案
    # 擁有者都無法執行了,哪裡來的權限給其他人使用?當然就是空的啦! ^_^
    

    檔案類型:file
    如果你想要知道某個檔案的基本資料,例如是屬於 ASCII 或者是 data 檔案,或者是 binary , 且其中有沒有使用到動態函式庫 (share library) 等等的資訊,就可以利用 file 這個指令來檢閱喔! 舉例來說:
    [root@linux ~]# file ~/.bashrc
    /root/.bashrc: ASCII text  <== 告訴我們是 ASCII 的純文字檔啊!
    [root@linux ~]# file /usr/bin/passwd
    /usr/bin/passwd: setuid ELF 32-bit LSB executable, Intel 80386, version 1 
    (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped
    # 資料可多了∼包括這個日 Set UID 2的檔案,使用 shared libs,
    # 適合於 Intel 的 386 以上機種的硬體,很清楚吧!
    [root@linux ~]# file /var/lib/slocate/slocate.db
    /var/lib/slocate/slocate.db: data  <== 這是 data 檔案!
    
    透過這個指令,我們可以簡單的先判斷這個檔案的格式為何喔!

    檔案的搜尋:
    檔案的搜尋可就厲害了!因為我們常常需要知道那個檔案放在哪裡,所以來談一談怎麼搜尋吧!在 Linux 底下也有相當優異的搜尋系統呦!通常 find 不很常用的!因為速度慢之外,也很操硬碟!通常我們都是先使用 whereis 或者是 locate 來檢查,如果真的找不到了,才以 find 來搜尋呦!為什麼呢?因為 whereis 與 locate 是利用資料庫來搜尋資料,所以相當的快速,而且並沒有實際的搜尋硬碟,比較省時間啦!


  • which (尋找『執行檔』)
  • [root@linux ~]# which [-a] command
    參數:
    -a :將所有可以找到的指令均列出,而不止第一個被找到的指令名稱
    範例:
    [root@linux ~]# which passwd
    /usr/bin/passwd
    [root@linux ~]# which traceroute -a
    /usr/sbin/traceroute
    /bin/traceroute
    
    這個指令是根據『PATH』這個環境變數所規範的路徑,去搜尋『執行檔』的檔名∼ 所以,重點是找出『執行檔』而已!且 which 後面接的是『完整檔名』喔!若加上 -a 參數,則可以列出所有的可以找到的同名執行檔,而非僅顯示第一個而已!


  • whereis (尋找特定檔案)
  • [root@linux ~]# whereis [-bmsu] 檔案或目錄名
    參數:
    -b    :只找 binary 的檔案
    -m    :只找在說明檔 manual 路徑下的檔案
    -s    :只找 source 來源檔案
    -u    :沒有說明檔的檔案!
    範例:
    [root@linux ~]# whereis passwd
    passwd: /usr/bin/passwd /etc/passwd /etc/passwd.OLD 
    /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
    # 任何與 passwd 有關的檔名都會被列出來∼
    
    [root@linux ~]# whereis -b passwd
    passwd: /usr/bin/passwd /etc/passwd /etc/passwd.OLD
    
    [root@linux ~]# whereis -m passwd
    passwd: /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
    
    等一下我們會提到 find 這個搜尋指令, find 是很強大的搜尋指令,但時間花用的很大! (因為 find 是直接搜尋硬碟,為如果你的硬碟比較老舊的話,嘿嘿!有的等的!) 這個時候 whereis 就相當的好用了!另外, whereis 可以加入參數來找尋相關的資料, 例如如果你是要找可執行檔 ( binary ) 那麼加上 -b 就可以啦!例如上面的範例針對 passwd 這支程式來說明!如果不加任何參數的話,那麼就將所有的資料列出來囉!

    那麼 whereis 到底是使用什麼咚咚呢?為何搜尋的速度會比 find 快這麼多?! 其實那也沒有什麼!這是因為 Linux 系統會將系統內的所有檔案都記錄在一個資料庫檔案裡面, 而當使用 whereis 或者是底下要說的 locate 時,都會以此資料庫檔案的內容為準, 因此,有的時後你還會發現使用這兩個執行檔時,會找到已經被殺掉的檔案! 而且也找不到最新的剛剛建立的檔案呢! 這就是因為這兩個指令是由資料庫當中的結果去搜尋檔案的所在啊!

    另外,基本上 Linux 每天會針對 Linux 主機上所有檔案的所在進行搜尋資料庫的更新, 更新的程式就是 updatedb ,你可以在 FC4 系統的 /etc/cron.daily/slocate.cron 這個檔案找到相關的機制呦!當然,也可以直接使用 /usr/bin/updatedb 來更新資料庫檔案呢!

  • locate
  • [root@linux ~]# locate filename
    [root@linux ~]# locate passwd
    /lib/security/pam_passwdqc.so
    /lib/security/pam_unix_passwd.so
    /usr/lib/kde3/kded_kpasswdserver.so
    /usr/lib/kde3/kded_kpasswdserver.la
    .......中間省略.......
    
    這個 locate 的使用更簡單,直接在後面輸入『檔案的部分名稱』後,就能夠得到結果。 舉上面的例子來說,我輸入 locate passwd ,那麼在完整檔名 (包含路徑名稱) 當中,只要有 passwd 在其中, 就會被顯示出來的!這也是個很方便好用的指令,如果您忘記某個檔案的完整檔名時∼∼

    但是,這個東西還是有使用上的限制呦!為什麼呢?您會發現使用 locate 來尋找資料的時候特別的快, 這是因為 locate 尋找的資料是由『已建立的資料庫 /var/lib/slocate/』 裡面的資料所搜尋到的,所以不用直接在去硬碟當中存取資料,呵呵!當然是很快速囉! 那麼有什麼限制呢?就是因為他是經由資料庫來搜尋的,而資料庫的建立預設是在每天執行一次 (每個 distribution 都不同, FC4 是每天更新資料庫一次!),所以當您新建立起來的檔案, 卻還在資料庫更新之前搜尋該檔案,那麼 locate 會告訴您『找不到!』呵呵!因為必須要更新資料庫呀!

    那麼我到底要建立哪些資料庫呢?是否全部都要建立?似乎不需要,這個時候, 你可以自己選擇需要建立檔案資料庫的目錄呢!你可以在 /etc/updatedb.conf 這個檔案內設定。 建議您使用預設值就好了,不過,在 /etc/updatedb.conf 裡面,請把『DAILY_UPDATE=no』改成 『DAILY_UPDATE=yes』就好了。至於修改的方法等到我們第三章提完 vi 後,您就會曉得囉∼ 當然啦,也可以自行手動執行 updatedb 即可!


  • find
  • [root@linux ~]# find [PATH] [option] [action]
    參數:
    1. 與時間有關的參數:
       -atime n :n 為數字,意義為在 n 天之前的『一天之內』被 access 過的檔案;
       -ctime n :n 為數字,意義為在 n 天之前的『一天之內』被 change 過狀態的檔案;
       -mtime n :n 為數字,意義為在 n 天之前的『一天之內』被 modification 過的檔案;
       -newer file :file 為一個存在的檔案,意思是說,只要檔案比 file 還要新,
                     就會被列出來∼
    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 搜尋。
    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.... 的屬性存在!
    4. 額外可進行的動作:
       -exec command :command 為其他指令,-exec 後面可再接額外的指令來處理搜尋到
                       的結果。
       -print        :將結果列印到螢幕上,這個動作是預設動作!
    範例:
    範例一:將過去系統上面 24 小時內有更動過內容 (mtime) 的檔案列出
    [root@linux ~]# find / -mtime 0
    # 那個 0 是重點!0 代表目前的時間,所以,從現在開始到 24 小時前,
    # 有變動過內容的檔案都會被列出來!那如果是三天前的 24 小時內?
    # find / -mtime 3 ,意思是說今天之前的 3*24 ~ 4*24 小時之間
    # 有變動過的檔案都被列出的意思!同時 -atime 與 -ctime 的用法相同。
    
    範例二:尋找 /etc 底下的檔案,如果檔案日期比 /etc/passwd 新就列出
    [root@linux ~]# find /etc -newer /etc/passwd
    # -newer 用在分辨兩個檔案之間的新舊關係是很有用的!
    
    範例三:搜尋 /home 底下屬於 dmtsai 的檔案
    [root@linux ~]# find /home -user dmtsai
    # 這個東西也很有用的∼當我們要找出任何一個使用者在系統當中的所有檔案時,
    # 就可以利用這個指令將屬於某個使用者的所有檔案都找出來喔!
    
    範例四:搜尋系統中不屬於任何人的檔案
    [root@linux ~]# find / -nouser
    # 透過這個指令,可以輕易的就找出那些不太正常的檔案。
    # 如果有找到不屬於系統任何人的檔案時,不要太緊張,
    # 那有時候是正常的∼尤其是您曾經以原始碼自行編譯軟體時。
    
    範例五:找出檔名為 passwd 這個檔案
    [root@linux ~]# find / -name passwd
    # 利用這個 -name 可以搜尋檔名啊!
    
    範例六:搜尋檔案屬性為 f (一般檔案) 的檔案
    [root@linux ~]# find /home -type f
    # 這個 -type 的屬性也很有幫助喔!尤其是要找出那些怪異的檔案,
    # 例如 socket 與 FIFO 檔案,可以用 find /var -type p 或 -type s 來找!
    
    範例七:搜尋檔案當中含有 SGID/SUID/SBIT 的屬性
    [root@linux ~]# find / -perm +7000 
    # 所謂的 7000 就是 ---s--s--t ,那麼只要含有 s 或 t 的就列出,
    # 所以當然要使用 +7000 ,使用 -7000 表示要含有 ---s--s--t 的所有三個權限,
    # 因此,就是 +7000 ∼瞭乎?
    
    範例八:將上個範例找到的檔案使用 ls -l 列出來∼
    [root@linux ~]# find / -perm +7000 -exec ls -l {} \;
    # 注意到,那個 -exec 後面的 ls -l 就是額外的指令,
    # 而那個 {} 代表的是『由 find 找到的內容』的意思∼所以, -exec ls -l {}
    # 就是將前面找到的那些檔案以 ls -l 列出長的資料!至於 \; 則是表示
    # -exec 的指令到此為止的意思∼意思是說,整個指令其實只有在 
    # -exec (裡面就是指令下達) \;
    # 也就是說,-exec 最後一定要以 \; 結束才行!這樣瞭解了嗎?!
    
    範例九:找出系統中,大於 1MB 的檔案
    [root@linux ~]# find / -size +1000k
    # 雖然在 man page 提到可以使用 M 與 G 分別代表 MB 與 GB,
    # 不過,俺卻試不出來這個功能∼所以,目前應該是僅支援到 c 與 k 吧!
    
    如果你要尋找一個檔案的話,那麼使用 find 會是一個不錯的主意! 他可以根據不同的參數來給予檔案的搜尋功能!例如你要尋找一個檔名為 httpd.conf 的檔案,你知道他應該是在 /etc 底下,那麼就可以使用『 find /etc -name httpd.conf 』嚕! 那如果你記得有一個檔案檔名包含了 httpd ,但是不知道全名怎辦?!呵呵,就用萬用字元 * 吧,如上以:『 find /etc -name '*httpd*' 』就可將檔名含有 httpd 的檔案都列出來囉!不過,由於 find 在尋找資料的時後相當的耗硬碟!所以沒事情不要使用 find 啦!有更棒的指令可以取代呦!那就是 whereislocate 囉!!

    但,不管怎麼說, find 在找尋特殊的檔案屬性,以及特殊的檔案權限 (SUID/SGID等等) 時, 是相當有用的工具程式之一!重要重要!

    本章習題練習:
    ( 要看答案請將滑鼠移動到『答:』底下的空白處,按下左鍵圈選空白處即可察看 )

    2002/06/26:第一次完成 2003/02/06:重新編排與加入 FAQ
    2003/02/07:加入 basename 與 dirname 的說明
    2004/03/15:將連結檔的內容移動至下一章節:Linux 磁碟與硬體管理
    2005/07/19:將舊的文章移動到 這裡 了。
    2005/07/20:呼呼!好不容易啊∼在被颱風尾掃到的七月份,終於寫完這個咚咚∼
    2005/07/21:在 find 部分,多增加了範例九,以及關於利用檔案大小 (size) 搜尋的功能。
    2005/07/25:在 SUID/SGID/SBIT 部分,依據 netman 與 小州 兄的建議,修改了部分的敘述!
    2006/04/09:在 rmdir 的範例內,少了一個 -p 的參數!
    2006/06/15:經由討論區網友 dm421 的通知,發現 chattr 的部分關於 d 寫錯了,已訂正。
    2006/08/22:增加 rm 的一些簡單的說明!尤其是『 rm ./-aaa- 』的刪除方法!