鳥哥的 Linux 私房菜
<<

6.1 目錄與路徑

由前一章Linux的檔案權限與目錄配置中透過FHS瞭解了Linux的『樹狀目錄』概念之後, 接下來就得要實際的來搞定一些基本的路徑問題了!這些目錄的問題當中,最重要的莫過於前一章也談過的『絕對路徑』與『相對路徑』的意義啦! 絕對/相對路徑的寫法並不相同,要特別注意。此外,當妳下達指令時,該指令是透過什麼功能來取得的? 這與PATH這個變數有關呢!底下就讓我們來談談囉!

6.1.1 相對路徑與絕對路徑

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

  • 絕對路徑:路徑的寫法『一定由根目錄 / 寫起』,例如: /usr/share/doc 這個目錄。
  • 相對路徑:路徑的寫法『不是由 / 寫起』,例如由 /usr/share/doc 要到 /usr/share/man 底下時,可以寫成: 『cd ../man』這就是相對路徑的寫法啦!相對路徑意指『相對於目前工作目錄的路徑!』
  • 相對路徑的用途

那麼相對路徑與絕對路徑有什麼了不起呀?喝!那可真的是了不起了!假設你寫了一個軟體, 這個軟體共需要三個目錄,分別是 etc, bin, man 這三個目錄,然而由於不同的人喜歡安裝在不同的目錄之下, 假設甲安裝的目錄是 /usr/local/packages/etc, /usr/local/packages/bin 及 /usr/local/packages/man ,不過乙卻喜歡安裝在 /home/packages/etc, /home/packages/bin, /home/packages/man 這三個目錄中,請問如果需要用到絕對路徑的話,那麼是否很麻煩呢?是的! 如此一來每個目錄下的東西就很難對應的起來!這個時候相對路徑的寫法就顯的特別的重要了!

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

  • 絕對路徑的用途

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



6.1.2 目錄的相關操作

我們之前稍微提到變換目錄的指令是cd,還有哪些可以進行目錄操作的指令呢? 例如建立目錄啊、刪除目錄之類的~還有,得要先知道的,就是有哪些比較特殊的目錄呢? 舉例來說,底下這些就是比較特殊的目錄,得要用力的記下來才行:

.         代表此層目錄
..        代表上一層目錄
-         代表前一個工作目錄
~         代表『目前使用者身份』所在的家目錄
~account  代表 account 這個使用者的家目錄(account是個帳號名稱)

需要特別注意的是:在所有目錄底下都會存在的兩個目錄,分別是『.』與『..』 分別代表此層與上層目錄的意思。那麼來思考一下底下這個例題:

例題:
請問在Linux底下,根目錄下有沒有上層目錄(..)存在?
答:
若使用『 ls -al / 』去查詢,可以看到根目錄下確實存在 . 與 .. 兩個目錄,再仔細的查閱, 可發現這兩個目錄的屬性與權限完全一致,這代表根目錄的上一層(..)與根目錄自己(.)是同一個目錄。

底下我們就來談一談幾個常見的處理目錄的指令吧:

  • cd:變換目錄
  • pwd:顯示目前的目錄
  • mkdir:建立一個新的目錄
  • rmdir:刪除一個空的目錄
  • cd (change directory, 變換目錄)

我們知道dmtsai這個使用者的家目錄是/home/dmtsai/,而root家目錄則是/root/,假設我以root身份在 Linux系統中,那麼簡單的說明一下這幾個特殊的目錄的意義是:

[dmtsai@study ~]$ su -  # 先切換身份成為 root 看看!
[root@study ~]# cd [相對路徑或絕對路徑]
# 最重要的就是目錄的絕對路徑與相對路徑,還有一些特殊目錄的符號囉!
[root@study ~]# cd ~dmtsai
# 代表去到 dmtsai 這個使用者的家目錄,亦即 /home/dmtsai
[root@study dmtsai]# cd ~
# 表示回到自己的家目錄,亦即是 /root 這個目錄
[root@study ~]# cd
# 沒有加上任何路徑,也還是代表回到自己家目錄的意思喔!
[root@study ~]# cd ..
# 表示去到目前的上層目錄,亦即是 /root 的上層目錄的意思;
[root@study /]# cd -
# 表示回到剛剛的那個目錄,也就是 /root 囉~
[root@study ~]# cd /var/spool/mail
# 這個就是絕對路徑的寫法!直接指定要去的完整路徑名稱!
[root@study mail]# cd ../postfix
# 這個是相對路徑的寫法,我們由/var/spool/mail 去到/var/spool/postfix 就這樣寫!

cd是Change Directory的縮寫,這是用來變換工作目錄的指令。注意,目錄名稱與cd指令之間存在一個空格。 一登入Linux系統後,每個帳號都會在自己帳號的家目錄中。那回到上一層目錄可以用『 cd .. 』。 利用相對路徑的寫法必須要確認你目前的路徑才能正確的去到想要去的目錄。例如上表當中最後一個例子, 你必須要確認你是在/var/spool/mail當中,並且知道在/var/spool當中有個mqueue的目錄才行啊~ 這樣才能使用cd ../postfix 去到正確的目錄說,否則就要直接輸入cd /var/spool/postfix 囉~

其實,我們的提示字元,亦即那個 [root@study ~]# 當中,就已經有指出目前的目錄了, 剛登入時會到自己的家目錄,而家目錄還有一個代碼,那就是『 ~ 』符號! 例如上面的例子可以發現,使用『 cd ~ 』可以回到個人的家目錄裡頭去呢! 另外,針對 cd 的使用方法,如果僅輸入 cd 時,代表的就是『 cd ~ 』的意思喔~ 亦即是會回到自己的家目錄啦!而那個『 cd - 』比較難以理解,請自行多做幾次練習,就會比較明白了。

Tips鳥哥的圖示 還是要一再地提醒,我們的 Linux 的預設指令列模式 (bash shell) 具有檔案補齊功能, 你要常常利用 [tab] 按鍵來達成你的目錄完整性啊!這可是個好習慣啊~可以避免你按錯鍵盤輸入錯字說~ ^_^

  • pwd (顯示目前所在的目錄)
[root@study ~]# pwd [-P]
選項與參數:
-P  :顯示出確實的路徑,而非使用連結 (link) 路徑。

範例:單純顯示出目前的工作目錄:
[root@study ~]# pwd
/root   <== 顯示出目錄啦~

範例:顯示出實際的工作目錄,而非連結檔本身的目錄名而已
[root@study ~]# cd /var/mail   <==注意,/var/mail是一個連結檔
[root@study mail]# pwd
/var/mail         <==列出目前的工作目錄
[root@study mail]# pwd -P
/var/spool/mail   <==怎麼回事?有沒有加 -P 差很多~
[root@study mail]# ls -ld /var/mail
lrwxrwxrwx. 1 root root 10 May  4 17:51 /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 的選項啦!他可以讓我們取得正確的目錄名稱,而不是以連結檔的路徑來顯示的。 如果你使用的是CentOS 7.x的話,剛剛好/var/mail是/var/spool/mail的連結檔, 所以,透過到/var/mail下達pwd -P就能夠知道這個選項的意義囉~ ^_^

  • mkdir (建立新目錄)
[root@study ~]# mkdir [-mp] 目錄名稱
選項與參數:
-m :設定檔案的權限喔!直接設定,不需要看預設權限 (umask) 的臉色~
-p :幫助你直接將所需要的目錄(包含上層目錄)遞迴建立起來!

範例:請到/tmp底下嘗試建立數個新目錄看看:
[root@study ~]# cd /tmp
[root@study tmp]# mkdir test    <==建立一名為 test 的新目錄
[root@study tmp]# mkdir test1/test2/test3/test4
mkdir: cannot create directory ‘test1/test2/test3/test4’: No such file or directory
# 話說,系統告訴我們,沒可能建立這個目錄啊!就是沒有目錄才要建立的!見鬼嘛?
[root@study tmp]# mkdir -p test1/test2/test3/test4
# 原來是要建 test4 上層沒先建 test3 之故!加了這個 -p 的選項,可以自行幫你建立多層目錄!

範例:建立權限為rwx--x--x的目錄
[root@study tmp]# mkdir -m 711 test2
[root@study tmp]# ls -ld test*
drwxr-xr-x. 2 root   root  6 Jun  4 19:03 test
drwxr-xr-x. 3 root   root 18 Jun  4 19:04 test1
drwx--x--x. 2 root   root  6 Jun  4 19:05 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 依序的建立起目錄!並且, 如果該目錄本來就已經存在時,系統也不會顯示錯誤訊息喔!挺快樂的吧! ^_^。 不過鳥哥不建議常用-p這個選項,因為擔心如果妳打錯字,那麼目錄名稱就會變的亂七八糟的!

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

  • rmdir (刪除『空』的目錄)
[root@study ~]# rmdir [-p] 目錄名稱
選項與參數:
-p :連同『上層』『空的』目錄也一起刪除

範例:將於mkdir範例中建立的目錄(/tmp底下)刪除掉!
[root@study tmp]# ls -ld test*   <==看看有多少目錄存在?
drwxr-xr-x. 2 root   root  6 Jun  4 19:03 test
drwxr-xr-x. 3 root   root 18 Jun  4 19:04 test1
drwx--x--x. 2 root   root  6 Jun  4 19:05 test2
[root@study tmp]# rmdir test   <==可直接刪除掉,沒問題
[root@study tmp]# rmdir test1  <==因為尚有內容,所以無法刪除!
rmdir: failed to remove ‘test1’: Directory not empty
[root@study tmp]# rmdir -p test1/test2/test3/test4
[root@study tmp]# ls -ld test*    <==您看看,底下的輸出中test與test1不見了!
drwx--x--x. 2 root   root  6 Jun  4 19:05 test2
# 瞧!利用 -p 這個選項,立刻就可以將 test1/test2/test3/test4 一次刪除~
# 不過要注意的是,這個 rmdir 僅能『刪除空的目錄』喔!

如果想要刪除舊有的目錄時,就使用rmdir吧!例如將剛剛建立的test殺掉,使用『 rmdir test 』即可!請注意呦!目錄需要一層一層的刪除才行!而且被刪除的目錄裡面必定不能存在其他的目錄或檔案! 這也是所謂的空的目錄(empty directory)的意思啊!那如果要將所有目錄下的東西都殺掉呢?! 這個時候就必須使用『 rm -r test 』囉!不過,還是使用 rmdir 比較不危險!你也可以嘗試以 -p 的選項加入,來刪除上層的目錄喔!



6.1.3 關於執行檔路徑的變數: $PATH

經過前一章FHS的說明後,我們知道查閱檔案屬性的指令ls完整檔名為:/bin/ls(這是絕對路徑), 那你會不會覺得很奇怪:『為什麼我可以在任何地方執行/bin/ls這個指令呢? 』 為什麼我在任何目錄下輸入 ls 就一定可以顯示出一些訊息而不會說找不到該 /bin/ls 指令呢? 這是因為環境變數 PATH 的幫助所致呀

當我們在執行一個指令的時候,舉例來說『ls』好了,系統會依照PATH的設定去每個PATH定義的目錄下搜尋檔名為ls的可執行檔, 如果在PATH定義的目錄中含有多個檔名為ls的可執行檔,那麼先搜尋到的同名指令先被執行!

現在,請下達『echo $PATH』來看看到底有哪些目錄被定義出來了? echo有『顯示、印出』的意思,而 PATH 前面加的 $ 表示後面接的是變數,所以會顯示出目前的 PATH !

範例:先用root的身份列出搜尋的路徑為何?
[root@study ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

範例:用dmtsai的身份列出搜尋的路徑為何?
[root@study ~]# exit    # 由之前的 su - 離開,變回原本的帳號!或再取得一個終端機皆可!
[dmtsai@study ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
# 記不記得我們前一章說過,目前 /bin 是連結到 /usr/bin 當中的喔!

PATH(一定是大寫)這個變數的內容是由一堆目錄所組成的,每個目錄中間用冒號(:)來隔開, 每個目錄是有『順序』之分的。仔細看一下上面的輸出,妳可以發現到無論是root還是dmtsai都有 /bin 或 /usr/bin 這個目錄在PATH變數內,所以當然就能夠在任何地方執行ls來找到/bin/ls執行檔囉!因為 /bin 在 CentOS 7 當中,就是連結到 /usr/bin 去的! 所以這兩個目錄內容會一模一樣!

我們用幾個範例來讓你瞭解一下,為什麼PATH是那麼重要的項目!

例題:
假設你是root,如果你將ls由/bin/ls移動成為/root/ls(可用『mv /bin/ls /root』指令達成),然後你自己本身也在/root目錄下, 請問(1)你能不能直接輸入ls來執行?(2)若不能,你該如何執行ls這個指令?(3)若要直接輸入ls即可執行,又該如何進行?
答:
由於這個例題的重點是將某個執行檔移動到非正規目錄去,所以我們先要進行底下的動作才行:(務必先使用 su - 切換成為root的身份)
[root@study ~]# mv /bin/ls /root
# mv 為移動,可將檔案在不同的目錄間進行移動作業
(1)接下來不論你在那個目錄底下輸入任何與ls相關的指令,都沒有辦法順利的執行ls了! 也就是說,你不能直接輸入ls來執行,因為/root這個目錄並不在PATH指定的目錄中, 所以,即使你在/root目錄下,也不能夠搜尋到ls這個指令!

(2)因為這個ls確實存在於/root底下,並不是被刪除了!所以我們可以透過使用絕對路徑或者是相對路徑直接指定這個執行檔檔名, 底下的兩個方法都能夠執行ls這個指令:
[root@study ~]# /root/ls  <==直接用絕對路徑指定該檔名
[root@study ~]# ./ls      <==因為在 /root 目錄下,就用./ls來指定
(3)如果想要讓root在任何目錄均可執行/root底下的ls,那麼就將/root加入PATH當中即可。 加入的方法很簡單,就像底下這樣:
[root@study ~]# PATH="${PATH}:/root"
上面這個作法就能夠將/root加入到執行檔搜尋路徑PATH中了!不相信的話請您自行使用『echo $PATH』去查看吧! 另外,除了 $PATH 之外,如果想要更明確的定義出變數的名稱,可以使用大括號 ${PATH} 來處理變數的呼叫喔! 如果確定這個例題進行沒有問題了,請將ls搬回/bin底下,不然系統會掛點的!
[root@study ~]# mv /root/ls /bin
某些情況下,即使你已經將 ls 搬回 /bin 了,不過系統還是會告知你無法處理 /root/ls 喔!很可能是因為指令參數被快取的關係。 不要緊張,只要登出 (exit) 再登入 (su -) 就可以繼續快樂的使用 ls 了!

例題:
如果我有兩個ls指令在不同的目錄中,例如/usr/local/bin/ls與/bin/ls那麼當我下達 ls 的時候,哪個ls會被執行?
答:
那還用說,就找出 ${PATH} 裡面哪個目錄先被查詢,則那個目錄下的指令就會被先執行了!所以用 dmtsai 帳號為例,他最先搜尋的是 /usr/local/bin, 所以 /usr/local/bin/ls 會先被執行喔!

例題:
為什麼 ${PATH} 搜尋的目錄不加入本目錄(.)?加入本目錄的搜尋不是也不錯?
答:
如果在PATH中加入本目錄(.)後,確實我們就能夠在指令所在目錄進行指令的執行了。 但是由於你的工作目錄並非固定(常常會使用cd來切換到不同的目錄), 因此能夠執行的指令會有變動(因為每個目錄底下的可執行檔都不相同嘛!),這對使用者來說並非好事。

另外,如果有個壞心使用者在/tmp底下做了一個指令,因為/tmp是大家都能夠寫入的環境,所以他當然可以這樣做。 假設該指令可能會竊取使用者的一些資料,如果你使用root的身份來執行這個指令,那不是很糟糕? 如果這個指令的名稱又是經常會被用到的ls時,那『中標』的機率就更高了!

所以,為了安全起見,不建議將『.』加入PATH的搜尋目錄中。

而由上面的幾個例題我們也可以知道幾件事情:

  • 不同身份使用者預設的PATH不同,預設能夠隨意執行的指令也不同(如root與dmtsai);
  • PATH是可以修改的;
  • 使用絕對路徑或相對路徑直接指定某個指令的檔名來執行,會比搜尋PATH來的正確;
  • 指令應該要放置到正確的目錄下,執行才會比較方便;
  • 本目錄(.)最好不要放到PATH當中。

對於PATH更詳細的『變數』說明,我們會在第三篇的bash shell中詳細說明的!


6.2 檔案與目錄管理

談了談目錄與路徑之後,再來討論一下關於檔案的一些基本管理吧!檔案與目錄的管理上,不外乎『顯示屬性』、 『拷貝』、『刪除檔案』及『移動檔案或目錄』等等,由於檔案與目錄的管理在 Linux 當中是很重要的, 尤其是每個人自己家目錄的資料也都需要注意管理!所以我們來談一談有關檔案與目錄的一些基礎管理部分吧!

6.2.1 檔案與目錄的檢視: ls

[root@study ~]# ls [-aAdfFhilnrRSt] 檔名或目錄名稱..
[root@study ~]# ls [--color={never,auto,always}] 檔名或目錄名稱..
[root@study ~]# ls [--full-time] 檔名或目錄名稱..
選項與參數:
-a  :全部的檔案,連同隱藏檔( 開頭為 . 的檔案) 一起列出來(常用)
-A  :全部的檔案,連同隱藏檔,但不包括 . 與 .. 這兩個目錄
-d  :僅列出目錄本身,而不是列出目錄內的檔案資料(常用)
-f  :直接列出結果,而不進行排序 (ls 預設會以檔名排序!)
-F  :根據檔案、目錄等資訊,給予附加資料結構,例如:
      *:代表可執行檔; /:代表目錄; =:代表 socket 檔案; |:代表 FIFO 檔案;
-h  :將檔案容量以人類較易讀的方式(例如 GB, KB 等等)列出來;
-i  :列出 inode 號碼,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@study ~]# ls -al ~
total 56
dr-xr-x---.  5 root root 4096 Jun  4 19:49 .
dr-xr-xr-x. 17 root root 4096 May  4 17:56 ..
-rw-------.  1 root root 1816 May  4 17:57 anaconda-ks.cfg
-rw-------.  1 root root 6798 Jun  4 19:53 .bash_history
-rw-r--r--.  1 root root   18 Dec 29  2013 .bash_logout
-rw-r--r--.  1 root root  176 Dec 29  2013 .bash_profile
-rw-rw-rw-.  1 root root  176 Dec 29  2013 .bashrc
-rw-r--r--.  1 root root  176 Jun  3 00:04 .bashrc_test
drwx------.  4 root root   29 May  6 00:14 .cache
drwxr-xr-x.  3 root root   17 May  6 00:14 .config
# 這個時候你會看到以 . 為開頭的幾個檔案,以及目錄檔 (.) (..) .config 等等,
# 不過,目錄檔檔名都是以深藍色顯示,有點不容易看清楚就是了。

範例二:承上題,不顯示顏色,但在檔名末顯示出該檔名代表的類型(type)
[root@study ~]# ls -alF --color=never  ~
total 56
dr-xr-x---.  5 root root 4096 Jun  4 19:49 ./
dr-xr-xr-x. 17 root root 4096 May  4 17:56 ../
-rw-------.  1 root root 1816 May  4 17:57 anaconda-ks.cfg
-rw-------.  1 root root 6798 Jun  4 19:53 .bash_history
-rw-r--r--.  1 root root   18 Dec 29  2013 .bash_logout
-rw-r--r--.  1 root root  176 Dec 29  2013 .bash_profile
-rw-rw-rw-.  1 root root  176 Dec 29  2013 .bashrc
-rw-r--r--.  1 root root  176 Jun  3 00:04 .bashrc_test
drwx------.  4 root root   29 May  6 00:14 .cache/
drwxr-xr-x.  3 root root   17 May  6 00:14 .config/
# 注意看到顯示結果的第一行,嘿嘿~知道為何我們會下達類似 ./command 
# 之類的指令了吧?因為 ./ 代表的是『目前目錄下』的意思啊!至於什麼是 FIFO/Socket ?
# 請參考前一章節的介紹啊!另外,那個.bashrc 時間僅寫2013,能否知道詳細時間?

範例三:完整的呈現檔案的修改時間 (modification time)
[root@study ~]# ls -al --full-time  ~
total 56
dr-xr-x---.  5 root root 4096 2015-06-04 19:49:54.520684829 +0800 .
dr-xr-xr-x. 17 root root 4096 2015-05-04 17:56:38.888000000 +0800 ..
-rw-------.  1 root root 1816 2015-05-04 17:57:02.326000000 +0800 anaconda-ks.cfg
-rw-------.  1 root root 6798 2015-06-04 19:53:41.451684829 +0800 .bash_history
-rw-r--r--.  1 root root   18 2013-12-29 10:26:31.000000000 +0800 .bash_logout
-rw-r--r--.  1 root root  176 2013-12-29 10:26:31.000000000 +0800 .bash_profile
-rw-rw-rw-.  1 root root  176 2013-12-29 10:26:31.000000000 +0800 .bashrc
-rw-r--r--.  1 root root  176 2015-06-03 00:04:16.916684829 +0800 .bashrc_test
drwx------.  4 root root   29 2015-05-06 00:14:56.960764950 +0800 .cache
drwxr-xr-x.  3 root root   17 2015-05-06 00:14:56.975764950 +0800 .config
# 請仔細看,上面的『時間』欄位變了喔!變成較為完整的格式。
# 一般來說, ls -al 僅列出目前短格式的時間,有時不會列出年份,
# 藉由 --full-time 可以查閱到比較正確的完整時間格式啊!

其實 ls 的用法還有很多,包括查閱檔案所在 i-node 號碼的 ls -i 選項,以及用來進行檔案排序的 -S 選項,還有用來查閱不同時間的動作的 --time=atime 等選項(更多時間說明請參考本章後面touch的說明)。而這些選項的存在都是因為 Linux 檔案系統記錄了很多有用的資訊的緣故。那麼 Linux 的檔案系統中,這些與權限、屬性有關的資料放在哪裡呢? 放在 i-node 裡面。關於這部分,我們會在下一章繼續為你作比較深入的介紹啊!

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



6.2.2 複製、刪除與移動: cp, rm, mv

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

  • cp (複製檔案或目錄)
[root@study ~]# cp [-adfilprsu] 來源檔(source) 目標檔(destination)
[root@study ~]# cp [options] source1 source2 source3 .... directory
選項與參數:
-a  :相當於 -dr --preserve=all 的意思,至於 dr 請參考下列說明;(常用)
-d  :若來源檔為連結檔的屬性(link file),則複製連結檔屬性而非檔案本身;
-f  :為強制(force)的意思,若目標檔案已經存在且無法開啟,則移除後再嘗試一次;
-i  :若目標檔(destination)已經存在時,在覆蓋時會先詢問動作的進行(常用)
-l  :進行硬式連結(hard link)的連結檔建立,而非複製檔案本身;
-p  :連同檔案的屬性(權限、用戶、時間)一起複製過去,而非使用預設屬性(備份常用);
-r  :遞迴持續複製,用於目錄的複製行為;(常用)
-s  :複製成為符號連結檔 (symbolic link),亦即『捷徑』檔案;
-u  :destination 比 source 舊才更新 destination,或 destination 不存在的情況下才複製。
--preserve=all :除了 -p 的權限相關參數外,還加入 SELinux 的屬性, links, xattr 等也複製了。
最後需要注意的,如果來源檔有兩個以上,則最後一個目的檔一定要是『目錄』才行!

複製(cp)這個指令是非常重要的,不同身份者執行這個指令會有不同的結果產生,尤其是那個-a, -p的選項, 對於不同身份來說,差異則非常的大!底下的練習中,有的身份為root有的身份為一般帳號 (在我這裡用 dmtsai 這個帳號), 練習時請特別注意身份的差別喔!好!開始來做複製的練習與觀察:

範例一:用root身份,將家目錄下的 .bashrc 複製到 /tmp 下,並更名為 bashrc
[root@study ~]# cp ~/.bashrc /tmp/bashrc
[root@study ~]# cp -i ~/.bashrc /tmp/bashrc
cp: overwrite `/tmp/bashrc'? n  <==n不覆蓋,y為覆蓋
# 重複作兩次動作,由於 /tmp 底下已經存在 bashrc 了,加上 -i 選項後,
# 則在覆蓋前會詢問使用者是否確定!可以按下 n 或者 y 來二次確認呢!

範例二:變換目錄到/tmp,並將/var/log/wtmp複製到/tmp且觀察屬性:
[root@study ~]# cd /tmp
[root@study tmp]# cp /var/log/wtmp . <==想要複製到目前的目錄,最後的 . 不要忘
[root@study tmp]# ls -l /var/log/wtmp wtmp
-rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 /var/log/wtmp
-rw-r--r--. 1 root root 28416 Jun 11 19:01 wtmp
# 注意上面的特殊字體,在不加任何選項的情況下,檔案的某些屬性/權限會改變;
# 這是個很重要的特性!要注意喔!還有,連檔案建立的時間也不一樣了!
# 那如果你想要將檔案的所有特性都一起複製過來該怎辦?可以加上 -a 喔!如下所示:

[root@study tmp]# cp -a /var/log/wtmp wtmp_2
[root@study tmp]# ls -l /var/log/wtmp wtmp_2
-rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 /var/log/wtmp
-rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 wtmp_2
# 瞭了吧!整個資料特性完全一模一樣ㄟ!真是不賴~這就是 -a 的特性!

這個 cp 的功能很多,由於我們常常會進行一些資料的複製,所以也會常常用到這個指令的。 一般來說,我們如果去複製別人的資料 (當然,該檔案你必須要有 read 的權限才行啊! ^_^) 時, 總是希望複製到的資料最後是我們自己的,所以,在預設的條件中, cp 的來源檔與目的檔的權限是不同的,目的檔的擁有者通常會是指令操作者本身。舉例來說, 上面的範例二中,由於我是 root 的身份,因此複製過來的檔案擁有者與群組就改變成為 root 所有了! 這樣說,可以明白嗎?^_^

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

範例三:複製 /etc/ 這個目錄下的所有內容到 /tmp 底下
[root@study tmp]# cp /etc/ /tmp
cp: omitting directory `/etc'   <== 如果是目錄則不能直接複製,要加上 -r 的選項
[root@study tmp]# cp -r /etc/ /tmp
# 還是要再次的強調喔! -r 是可以複製目錄,但是,檔案與目錄的權限可能會被改變
# 所以,也可以利用『 cp -a /etc /tmp 』來下達指令喔!尤其是在備份的情況下!

範例四:將範例一複製的 bashrc 建立一個連結檔 (symbolic link)
[root@study tmp]# ls -l bashrc
-rw-r--r--. 1 root root 176 Jun 11 19:01 bashrc  <==先觀察一下檔案情況
[root@study tmp]# cp -s bashrc bashrc_slink
[root@study tmp]# cp -l bashrc bashrc_hlink
[root@study tmp]# ls -l bashrc*
-rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc         <==與原始檔案不太一樣了!
-rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc_hlink
lrwxrwxrwx. 1 root root   6 Jun 11 19:06 bashrc_slink -> bashrc

範例四可有趣了!使用 -l 及 -s 都會建立所謂的連結檔(link file),但是這兩種連結檔卻有不一樣的情況。這是怎麼一回事啊? 那個 -l 就是所謂的實體連結(hard link),至於 -s 則是符號連結(symbolic link), 簡單來說,bashrc_slink 是一個『捷徑』,這個捷徑會連結到bashrc去!所以你會看到檔名右側會有個指向(->)的符號!

至於bashrc_hlink檔案與bashrc的屬性與權限完全一模一樣,與尚未進行連結前的差異則是第二欄的link數由1變成2了! 鳥哥這裡先不介紹實體連結,因為實體連結涉及 i-node 的相關知識,我們下一章談到檔案系統(filesystem)時再來討論這個問題。

範例五:若 ~/.bashrc 比 /tmp/bashrc 新才複製過來
[root@study tmp]# cp -u ~/.bashrc /tmp/bashrc
# 這個 -u 的特性,是在目標檔案與來源檔案有差異時,才會複製的。
# 所以,比較常被用於『備份』的工作當中喔! ^_^

範例六:將範例四造成的 bashrc_slink 複製成為 bashrc_slink_1 與bashrc_slink_2
[root@study tmp]# cp bashrc_slink bashrc_slink_1
[root@study tmp]# cp -d bashrc_slink bashrc_slink_2
[root@study tmp]# ls -l bashrc bashrc_slink*
-rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc
lrwxrwxrwx. 1 root root   6 Jun 11 19:06 bashrc_slink -> bashrc
-rw-r--r--. 1 root root 176 Jun 11 19:09 bashrc_slink_1            <==與原始檔案相同
lrwxrwxrwx. 1 root root   6 Jun 11 19:10 bashrc_slink_2 -> bashrc  <==是連結檔!
# 這個例子也是很有趣喔!原本複製的是連結檔,但是卻將連結檔的實際檔案複製過來了
# 也就是說,如果沒有加上任何選項時,cp複製的是原始檔案,而非連結檔的屬性!
# 若要複製連結檔的屬性,就得要使用 -d 的選項了!如 bashrc_slink_2 所示。

範例七:將家目錄的 .bashrc 及 .bash_history 複製到 /tmp 底下
[root@study tmp]# cp ~/.bashrc ~/.bash_history /tmp
# 可以將多個資料一次複製到同一個目錄去!最後面一定是目錄!
例題:
你能否使用 dmtsai 的身份,完整的複製/var/log/wtmp檔案到/tmp底下,並更名為dmtsai_wtmp呢?
答:
實際做看看的結果如下:
[dmtsai@study ~]$ cp -a /var/log/wtmp /tmp/dmtsai_wtmp
[dmtsai@study ~]$ ls -l /var/log/wtmp /tmp/dmtsai_wtmp
-rw-rw-r--. 1 dmtsai dmtsai 28416  6月 11 18:56 /tmp/dmtsai_wtmp
-rw-rw-r--. 1 root   utmp   28416  6月 11 18:56 /var/log/wtmp
由於 dmtsai 的身份並不能隨意修改檔案的擁有者與群組,因此雖然能夠複製wtmp的相關權限與時間等屬性, 但是與擁有者、群組相關的,原本 dmtsai 身份無法進行的動作,即使加上 -a 選項,也是無法達成完整複製權限的!

總之,由於 cp 有種種的檔案屬性與權限的特性,所以,在複製時,你必須要清楚的瞭解到:

  • 是否需要完整的保留來源檔案的資訊?
  • 來源檔案是否為連結檔 (symbolic link file)?
  • 來源檔是否為特殊的檔案,例如 FIFO, socket 等?
  • 來源檔是否為目錄?
  • rm (移除檔案或目錄)
[root@study ~]# rm [-fir] 檔案或目錄
選項與參數:
-f  :就是 force 的意思,忽略不存在的檔案,不會出現警告訊息;
-i  :互動模式,在刪除前會詢問使用者是否動作
-r  :遞迴刪除啊!最常用在目錄的刪除了!這是非常危險的選項!!!

範例一:將剛剛在 cp 的範例中建立的 bashrc 刪除掉!
[root@study ~]# cd /tmp
[root@study tmp]# rm -i bashrc
rm: remove regular file `bashrc'? y
# 如果加上 -i 的選項就會主動詢問喔,避免你刪除到錯誤的檔名!

範例二:透過萬用字元*的幫忙,將/tmp底下開頭為bashrc的檔名通通刪除:
[root@study tmp]# rm -i bashrc*
# 注意那個星號,代表的是 0 到無窮多個任意字元喔!很好用的東西!

範例三:將 cp 範例中所建立的 /tmp/etc/ 這個目錄刪除掉!
[root@study tmp]# rmdir /tmp/etc
rmdir: failed to remove '/tmp/etc': Directory not empty   <== 刪不掉啊!因為這不是空的目錄!
[root@study tmp]# rm -r /tmp/etc
rm: descend into directory `/tmp/etc'? y
rm: remove regular file `/tmp/etc/fstab'? y
rm: remove regular empty file `/tmp/etc/crypttab'? ^C  <== 按下 [crtl]+c 中斷
.....(中間省略).....
# 因為身份是 root ,預設已經加入了 -i 的選項,所以你要一直按 y 才會刪除!
# 如果不想要繼續按 y ,可以按下『 [ctrl]-c 』來結束 rm 的工作。
# 這是一種保護的動作,如果確定要刪除掉此目錄而不要詢問,可以這樣做:
[root@study tmp]# \rm -r /tmp/etc
# 在指令前加上反斜線,可以忽略掉 alias 的指定選項喔!至於 alias 我們在bash再談!
# 拜託!這個範例很可怕!你不要刪錯了!刪除 /etc 系統是會掛掉的!

範例四:刪除一個帶有 - 開頭的檔案
[root@study tmp]# touch ./-aaa-  <==touch這個指令可以建立空檔案!
[root@study tmp]# ls -l 
-rw-r--r--. 1 root   root       0 Jun 11 19:22 -aaa-  <==檔案大小為0,所以是空檔案
[root@study tmp]# rm -aaa-
rm: invalid option -- 'a'                    <== 因為 "-" 是選項嘛!所以系統誤判了!
Try 'rm ./-aaa-' to remove the file `-aaa-'. <== 新的 bash 有給建議的
Try 'rm --help' for more information.
[root@study tmp]# rm ./-aaa-

這是移除的指令(remove),要注意的是,通常在Linux系統下,為了怕檔案被 root 誤殺,所以很多 distributions 都已經預設加入 -i 這個選項了!而如果要連目錄下的東西都一起殺掉的話, 例如子目錄裡面還有子目錄時,那就要使用 -r 這個選項了!不過,使用『 rm -r 』這個指令之前,請千萬注意了,因為該目錄或檔案『肯定』會被 root 殺掉!因為系統不會再次詢問你是否要砍掉呦!所以那是個超級嚴重的指令下達呦! 得特別注意!不過,如果你確定該目錄不要了,那麼使用 rm -r 來循環殺掉是不錯的方式!

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

  • mv (移動檔案與目錄,或更名)
[root@study ~]# mv [-fiu] source destination
[root@study ~]# mv [options] source1 source2 source3 .... directory
選項與參數:
-f  :force 強制的意思,如果目標檔案已經存在,不會詢問而直接覆蓋;
-i  :若目標檔案 (destination) 已經存在時,就會詢問是否覆蓋!
-u  :若目標檔案已經存在,且 source 比較新,才會更新 (update)

範例一:複製一檔案,建立一目錄,將檔案移動到目錄中
[root@study ~]# cd /tmp
[root@study tmp]# cp ~/.bashrc bashrc
[root@study tmp]# mkdir mvtest
[root@study tmp]# mv bashrc mvtest
# 將某個檔案移動到某個目錄去,就是這樣做!

範例二:將剛剛的目錄名稱更名為 mvtest2
[root@study tmp]# mv mvtest mvtest2 <== 這樣就更名了!簡單~
# 其實在 Linux 底下還有個有趣的指令,名稱為 rename ,
# 該指令專職進行多個檔名的同時更名,並非針對單一檔名變更,與mv不同。請man rename。

範例三:再建立兩個檔案,再全部移動到 /tmp/mvtest2 當中
[root@study tmp]# cp ~/.bashrc bashrc1
[root@study tmp]# cp ~/.bashrc bashrc2
[root@study tmp]# mv bashrc1 bashrc2 mvtest2
# 注意到這邊,如果有多個來源檔案或目錄,則最後一個目標檔一定是『目錄!』
# 意思是說,將所有的資料移動到該目錄的意思!

這是搬移 (move) 的意思!當你要移動檔案或目錄的時後,呵呵!這個指令就很重要啦! 同樣的,你也可以使用 -u ( update )來測試新舊檔案,看看是否需要搬移囉! 另外一個用途就是『變更檔名!』,我們可以很輕易的使用 mv 來變更一個檔案的檔名呢!不過,在 Linux 才有的指令當中,有個 rename , 可以用來更改大量檔案的檔名,你可以利用 man rename 來查閱一下,也是挺有趣的指令喔!



6.2.3 取得路徑的檔案名稱與目錄名稱

每個檔案的完整檔名包含了前面的目錄與最終的檔名,而每個檔名的長度都可以到達 255 個字元耶! 那麼你怎麼知道那個是檔名?那個是目錄名?嘿嘿!就是利用斜線 (/) 來分辨啊! 其實,取得檔名或者是目錄名稱,一般的用途應該是在寫程式的時候用來判斷之用的啦~ 所以,這部分的指令可以用在第三篇內的 shell scripts 裡頭喔! 底下我們簡單的以幾個範例來談一談 basename 與 dirname 的用途!

[root@study ~]# basename /etc/sysconfig/network
network         <== 很簡單!就取得最後的檔名~
[root@study ~]# dirname /etc/sysconfig/network
/etc/sysconfig  <== 取得的變成目錄名了!

6.3 檔案內容查閱

如果我們要查閱一個檔案的內容時,該如何是好呢?這裡有相當多有趣的指令可以來分享一下: 最常使用的顯示檔案內容的指令可以說是 cat 與 more 及 less 了!此外,如果我們要查看一個很大型的檔案 (好幾百MB時),但是我們只需要後端的幾行字而已,那麼該如何是好?呵呵!用 tail 呀,此外, tac 這個指令也可以達到這個目的喔!好了,說說各個指令的用途吧!

  • cat  由第一行開始顯示檔案內容
  • tac  從最後一行開始顯示,可以看出 tac 是 cat 的倒著寫!
  • nl   顯示的時候,順道輸出行號!
  • more 一頁一頁的顯示檔案內容
  • less 與 more 類似,但是比 more 更好的是,他可以往前翻頁!
  • head 只看頭幾行
  • tail 只看尾巴幾行
  • od   以二進位的方式讀取檔案內容!

6.3.1 直接檢視檔案內容

直接查閱一個檔案的內容可以使用 cat/tac/nl 這幾個指令啊!

  • cat (concatenate)
[root@study ~]# cat [-AbEnTv]
選項與參數:
-A  :相當於 -vET 的整合選項,可列出一些特殊字符而不是空白而已;
-b  :列出行號,僅針對非空白行做行號顯示,空白行不標行號!
-E  :將結尾的斷行字元 $ 顯示出來;
-n  :列印出行號,連同空白行也會有行號,與 -b 的選項不同;
-T  :將 [tab] 按鍵以 ^I 顯示出來;
-v  :列出一些看不出來的特殊字符

範例一:檢閱 /etc/issue 這個檔案的內容
[root@study ~]# cat /etc/issue
\S
Kernel \r on an \m

範例二:承上題,如果還要加印行號呢?
[root@study ~]# cat -n /etc/issue
     1  \S
     2  Kernel \r on an \m
     3
# 所以這個檔案有三行!看到了吧!可以印出行號呢!這對於大檔案要找某個特定的行時,有點用處!
# 如果不想要編排空白行的行號,可以使用『cat -b /etc/issue』,自己測試看看:

範例三:將 /etc/man_db.conf 的內容完整的顯示出來(包含特殊字元)
[root@study ~]# cat -A /etc/man_db.conf
# $
....(中間省略)....
MANPATH_MAP^I/bin^I^I^I/usr/share/man$
MANPATH_MAP^I/usr/bin^I^I/usr/share/man$
MANPATH_MAP^I/sbin^I^I^I/usr/share/man$
MANPATH_MAP^I/usr/sbin^I^I/usr/share/man$
.....(底下省略).....
# 上面的結果限於篇幅,鳥哥刪除掉很多資料了。另外,輸出的結果並不會有特殊字體,
# 鳥哥上面的特殊字體是要讓您發現差異點在哪裡就是了。基本上,在一般的環境中,
# 使用 [tab] 與空白鍵的效果差不多,都是一堆空白啊!我們無法知道兩者的差別。
# 此時使用 cat -A 就能夠發現那些空白的地方是啥鬼東西了![tab]會以 ^I 表示,
# 斷行字元則是以 $ 表示,所以你可以發現每一行後面都是 $ 啊!不過斷行字元
# 在Windows/Linux則不太相同,Windows的斷行字元是 ^M$ 囉。
# 這部分我們會在第十章 vim 軟體的介紹時,再次的說明到喔!

嘿嘿!Linux 裡面有『貓』指令?喔!不是的, cat 是 Concatenate (連續) 的簡寫, 主要的功能是將一個檔案的內容連續的印出在螢幕上面!例如上面的例子中,我們將 /etc/issue 印出來!如果加上 -n 或 -b 的話,則每一行前面還會加上行號呦!

鳥哥個人是比較少用 cat 啦!畢竟當你的檔案內容的行數超過 40 行以上,嘿嘿!根本來不及在螢幕上看到結果! 所以,配合等一下要介紹的 more 或者是 less 來執行比較好!此外,如果是一般的 DOS 檔案時,就需要特別留意一些奇奇怪怪的符號了, 例如斷行與 [tab] 等,要顯示出來,就得加入 -A 之類的選項了!

  • tac (反向列示)
[root@study ~]# tac /etc/issue

Kernel \r on an \m
\S
# 嘿嘿!與剛剛上面的範例一比較,是由最後一行先顯示喔!

tac 這個好玩了!怎麼說呢?詳細的看一下, cat 與 tac ,有沒有發現呀!對啦! tac 剛好是將 cat 反寫過來,所以他的功能就跟 cat 相反啦, cat 是由『第一行到最後一行連續顯示在螢幕上』,而 tac 則是『 由最後一行到第一行反向在螢幕上顯示出來 』,很好玩吧!

  • nl (添加行號列印)
[root@study ~]# nl [-bnw] 檔案
選項與參數:
-b  :指定行號指定的方式,主要有兩種:
      -b a :表示不論是否為空行,也同樣列出行號(類似 cat -n);
      -b t :如果有空行,空的那一行不要列出行號(預設值);
-n  :列出行號表示的方法,主要有三種:
      -n ln :行號在螢幕的最左方顯示;
      -n rn :行號在自己欄位的最右方顯示,且不加 0 ;
      -n rz :行號在自己欄位的最右方顯示,且加 0 ;
-w  :行號欄位的佔用的字元數。

範例一:用 nl 列出 /etc/issue 的內容
[root@study ~]# nl /etc/issue
     1  \S
     2  Kernel \r on an \m

# 注意看,這個檔案其實有三行,第三行為空白(沒有任何字元),
# 因為他是空白行,所以 nl 不會加上行號喔!如果確定要加上行號,可以這樣做:

[root@study ~]# nl -b a /etc/issue
     1  \S
     2  Kernel \r on an \m
     3
# 呵呵!行號加上來囉~那麼如果要讓行號前面自動補上 0 呢?可這樣

[root@study ~]# nl -b a -n rz /etc/issue
000001  \S
000002  Kernel \r on an \m
000003
# 嘿嘿!自動在自己欄位的地方補上 0 了~預設欄位是六位數,如果想要改成 3 位數?

[root@study ~]# nl -b a -n rz -w 3 /etc/issue
001     \S
002     Kernel \r on an \m
003
# 變成僅有 3 位數囉~

nl 可以將輸出的檔案內容自動的加上行號!其預設的結果與 cat -n 有點不太一樣, nl 可以將行號做比較多的顯示設計,包括位數與是否自動補齊 0 等等的功能呢。



6.3.2 可翻頁檢視

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

  • more (一頁一頁翻動)
[root@study ~]# more /etc/man_db.conf
#
#
# This file is used by the man-db package to configure the man and cat paths.
# It is also used to provide a manpath for those without one by examining
# their PATH environment variable. For details see the manpath(5) man page.
#
.....(中間省略).....
--More--(28%)  <== 重點在這一行喔!你的游標也會在這裡等待你的指令

仔細的給他看到上面的範例,如果 more 後面接的檔案內容行數大於螢幕輸出的行數時, 就會出現類似上面的圖示。重點在最後一行,最後一行會顯示出目前顯示的百分比, 而且還可以在最後一行輸入一些有用的指令喔!在 more 這個程式的運作過程中,你有幾個按鍵可以按的:

  • 空白鍵 (space):代表向下翻一頁;
  • Enter         :代表向下翻『一行』;
  • /字串         :代表在這個顯示的內容當中,向下搜尋『字串』這個關鍵字;
  • :f            :立刻顯示出檔名以及目前顯示的行數;
  • q             :代表立刻離開 more ,不再顯示該檔案內容。
  • b 或 [ctrl]-b :代表往回翻頁,不過這動作只對檔案有用,對管線無用。

要離開 more 這個指令的顯示工作,可以按下 q 就能夠離開了。而要向下翻頁,就使用空白鍵即可。 比較有用的是搜尋字串的功能,舉例來說,我們使用『 more /etc/man_db.conf 』來觀察該檔案, 若想要在該檔案內搜尋 MANPATH 這個字串時,可以這樣做:

[root@study ~]# more /etc/man_db.conf
#
#
# This file is used by the man-db package to configure the man and cat paths.
# It is also used to provide a manpath for those without one by examining
# their PATH environment variable. For details see the manpath(5) man page.
#
....(中間省略)....
/MANPATH   <== 輸入了 / 之後,游標就會自動跑到最底下一行等待輸入!

如同上面的說明,輸入了 / 之後,游標就會跑到最底下一行,並且等待你的輸入, 你輸入了字串並按下[enter]之後,嘿嘿! more 就會開始向下搜尋該字串囉~而重複搜尋同一個字串, 可以直接按下 n 即可啊!最後,不想要看了,就按下 q 即可離開 more 啦!

  • less (一頁一頁翻動)
[root@study ~]# less /etc/man_db.conf
#
#
# This file is used by the man-db package to configure the man and cat paths.
# It is also used to provide a manpath for those without one by examining
# their PATH environment variable. For details see the manpath(5) man page.
#
.....(中間省略).....
:   <== 這裡可以等待你輸入指令!

less 的用法比起 more 又更加的有彈性,怎麼說呢?在 more 的時候,我們並沒有辦法向前面翻, 只能往後面看,但若使用了 less 時,呵呵!就可以使用 [pageup] [pagedown] 等按鍵的功能來往前往後翻看文件,你瞧,是不是更容易使用來觀看一個檔案的內容了呢!

除此之外,在 less 裡頭可以擁有更多的『搜尋』功能喔!不止可以向下搜尋,也可以向上搜尋~ 實在是很不錯用~基本上,可以輸入的指令有:

  • 空白鍵    :向下翻動一頁;
  • [pagedown]:向下翻動一頁;
  • [pageup]  :向上翻動一頁;
  • /字串     :向下搜尋『字串』的功能;
  • ?字串     :向上搜尋『字串』的功能;
  • n         :重複前一個搜尋 (與 / 或 ? 有關!)
  • N         :反向的重複前一個搜尋 (與 / 或 ? 有關!)
  • g         :前進到這個資料的第一行去;
  • G         :前進到這個資料的最後一行去 (注意大小寫);
  • q         :離開 less 這個程式;

查閱檔案內容還可以進行搜尋的動作~瞧~ less 是否很不錯用啊! 其實 less 還有很多的功能喔!詳細的使用方式請使用 man less 查詢一下啊! ^_^

你是否會覺得 less 使用的畫面與環境與 man page 非常的類似呢?沒錯啦!因為man這個指令就是呼叫 less 來顯示說明文件的內容的! 現在你是否覺得 less 很重要呢? ^_^



6.3.3 資料擷取

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

  • head (取出前面幾行)
[root@study ~]# head [-n number] 檔案 
選項與參數:
-n  :後面接數字,代表顯示幾行的意思

[root@study ~]# head /etc/man_db.conf
# 預設的情況中,顯示前面十行!若要顯示前 20 行,就得要這樣:
[root@study ~]# head -n 20 /etc/man_db.conf

範例:如果後面100行的資料都不列印,只列印/etc/man_db.conf的前面幾行,該如何是好?
[root@study ~]# head -n -100 /etc/man_db.conf

head 的英文意思就是『頭』啦,那麼這個東西的用法自然就是顯示出一個檔案的前幾行囉! 沒錯!就是這樣!若沒有加上 -n 這個選項時,預設只顯示十行,若只要一行呢?那就加入『 head -n 1 filename 』即可!

另外那個 -n 選項後面的參數較有趣,如果接的是負數,例如上面範例的-n -100時,代表列前的所有行數, 但不包括後面100行。舉例來說 CentOS 7.1 的 /etc/man_db.conf 共有131行,則上述的指令『head -n -100 /etc/man_db.conf』 就會列出前面31行,後面100行不會列印出來了。這樣說,比較容易懂了吧? ^_^

  • tail (取出後面幾行)
[root@study ~]# tail [-n number] 檔案 
選項與參數:
-n  :後面接數字,代表顯示幾行的意思
-f  :表示持續偵測後面所接的檔名,要等到按下[ctrl]-c才會結束tail的偵測

[root@study ~]# tail /etc/man_db.conf
# 預設的情況中,顯示最後的十行!若要顯示最後的 20 行,就得要這樣:
[root@study ~]# tail -n 20 /etc/man_db.conf

範例一:如果不知道/etc/man_db.conf有幾行,卻只想列出100行以後的資料時?
[root@study ~]# tail -n +100 /etc/man_db.conf

範例二:持續偵測/var/log/messages的內容
[root@study ~]# tail -f /var/log/messages
  <==要等到輸入[crtl]-c之後才會離開tail這個指令的偵測!

有 head 自然就有 tail ( 尾巴 ) 囉!沒錯!這個 tail 的用法跟 head 的用法差不多類似,只是顯示的是後面幾行就是了!預設也是顯示十行,若要顯示非十行,就加 -n number 的選項即可。

範例一的內容就有趣啦!其實與head -n -xx有異曲同工之妙。當下達『tail -n +100 /etc/man_db.conf』 代表該檔案從100行以後都會被列出來,同樣的,在man_db.conf共有131行,因此第100~131行就會被列出來啦! 前面的99行都不會被顯示出來喔!

至於範例二中,由於/var/log/messages隨時會有資料寫入,你想要讓該檔案有資料寫入時就立刻顯示到螢幕上, 就利用 -f 這個選項,他可以一直偵測/var/log/messages這個檔案,新加入的資料都會被顯示到螢幕上。 直到你按下[crtl]-c才會離開tail的偵測喔!由於 messages 必須要 root 權限才能看,所以該範例得要使用 root 來查詢喔!

例題:
假如我想要顯示 /etc/man_db.conf 的第 11 到第 20 行呢?
答:
這個應該不算難,想一想,在第 11 到第 20 行,那麼我取前 20 行,再取後十行,所以結果就是:『 head -n 20 /etc/man_db.conf | tail -n 10 』,這樣就可以得到第 11 到第 20 行之間的內容了!

這兩個指令中間有個管線 (|) 的符號存在,這個管線的意思是:『前面的指令所輸出的訊息,請透過管線交由後續的指令繼續使用』的意思。 所以, head -n 20 /etc/man_db.conf 會將檔案內的 20 行取出來,但不輸出到螢幕上,而是轉交給後續的 tail 指令繼續處理。 因此 tail 『不需要接檔名』,因為 tail 所需要的資料是來自於 head 處理後的結果!這樣說,有沒有理解?

更多的管線命令,我們會在第三篇繼續解釋的!

例題:
承上一題,那如果我想要列出正確的行號呢?就是螢幕上僅列出 /etc/man_db.conf 的第 11 到第 20 行,且有行號存在?
答:
我們可以透過 cat -n 來帶出行號,然後再透過 head/tail 來擷取資料即可!所以就變成如下的模樣了:
cat -n /etc/man_db.conf | head -n 20 | tail -n 10



6.3.4 非純文字檔: od

我們上面提到的,都是在查閱純文字檔的內容。那麼萬一我們想要查閱非文字檔,舉例來說,例如 /usr/bin/passwd 這個執行檔的內容時, 又該如何去讀出資訊呢?事實上,由於執行檔通常是 binary file ,使用上頭提到的指令來讀取他的內容時, 確實會產生類似亂碼的資料啊!那怎麼辦?沒關係,我們可以利用 od 這個指令來讀取喔!

[root@study ~]# 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 ;

範例一:請將/usr/bin/passwd的內容使用ASCII方式來展現!
[root@study ~]# od -t c /usr/bin/passwd
0000000 177   E   L   F 002 001 001  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020 003  \0   >  \0 001  \0  \0  \0 364   3  \0  \0  \0  \0  \0  \0
0000040   @  \0  \0  \0  \0  \0  \0  \0   x   e  \0  \0  \0  \0  \0  \0
0000060  \0  \0  \0  \0   @  \0   8  \0  \t  \0   @  \0 035  \0 034  \0
0000100 006  \0  \0  \0 005  \0  \0  \0   @  \0  \0  \0  \0  \0  \0  \0
.....(後面省略)....
# 最左邊第一欄是以 8 進位來表示bytes數。以上面範例來說,第二欄0000020代表開頭是
# 第 16 個 byes (2x8) 的內容之意。

範例二:請將/etc/issue這個檔案的內容以8進位列出儲存值與ASCII的對照表
[root@study ~]# od -t oCc /etc/issue
0000000 134 123 012 113 145 162 156 145 154 040 134 162 040 157 156 040
          \   S  \n   K   e   r   n   e   l       \   r       o   n
0000020 141 156 040 134 155 012 012
          a   n       \   m  \n  \n
0000027
# 如上所示,可以發現每個字元可以對應到的數值為何!要注意的是,該數值是 8 進位喔!
# 例如 S 對應的記錄數值為 123 ,轉成十進位:1x8^2+2x8+3=83。

利用這個指令,可以將 data file 或者是 binary file 的內容資料給他讀出來喔! 雖然讀出的來數值預設是使用非文字檔,亦即是 16 進位的數值來顯示的, 不過,我們還是可以透過 -t c 的選項與參數來將資料內的字元以 ASCII 類型的字元來顯示, 雖然對於一般使用者來說,這個指令的用處可能不大,但是對於工程師來說, 這個指令可以將 binary file 的內容作一個大致的輸出,他們可以看得出東西的啦~ ^_^

如果對純文字檔使用這個指令,你甚至可以發現到 ASCII 與字元的對照表!非常有趣! 例如上述的範例二,你可以發現到每個英文字 S 對照到的數字都是 123,轉成十進位你就能夠發現那是 83 囉! 如果你有任何程式語言的書,拿出來對照一下 ASCII 的對照表,就能夠發現真是正確啊!呵呵!

例題:
我不想找 google,想要立刻找到 password 這幾個字的 ASCII 對照,該如何透過 od 來判斷?
答:
其實可以透過剛剛上一個小節談到的管線命令來處理!如下所示:
echo password | od -t oCc
echo 可以在螢幕上面顯示任何資訊,而這個資訊不由螢幕輸出,而是傳給 od 去繼續處理!就可以得到 ASCII code 對照囉!



6.3.5 修改檔案時間或建置新檔: touch

我們在 ls 這個指令的介紹時,有稍微提到每個檔案在linux底下都會記錄許多的時間參數, 其實是有三個主要的變動時間,那麼三個時間的意義是什麼呢?

  • modification time (mtime)
    當該檔案的『內容資料』變更時,就會更新這個時間!內容資料指的是檔案的內容,而不是檔案的屬性或權限喔!

  • status time (ctime)
    當該檔案的『狀態 (status)』改變時,就會更新這個時間,舉例來說,像是權限與屬性被更改了,都會更新這個時間啊。

  • access time (atime)
    當『該檔案的內容被取用』時,就會更新這個讀取時間 (access)。舉例來說,我們使用 cat 去讀取 /etc/man_db.conf , 就會更新該檔案的 atime 了。

這是個挺有趣的現象,舉例來說,我們來看一看你自己的 /etc/man_db.conf 這個檔案的時間吧!

[root@study ~]# date; ls -l /etc/man_db.conf ; ls -l --time=atime /etc/man_db.conf ; \
> ls -l --time=ctime /etc/man_db.conf # 這兩行其實是同一行喔!用分號隔開
Tue Jun 16 00:43:17 CST 2015  # 目前的時間啊!
-rw-r--r--. 1 root root 5171 Jun 10  2014 /etc/man_db.conf  # 在 2014/06/10 建立的內容(mtime)
-rw-r--r--. 1 root root 5171 Jun 15 23:46 /etc/man_db.conf  # 在 2015/06/15 讀取過內容(atime)
-rw-r--r--. 1 root root 5171 May  4 17:54 /etc/man_db.conf  # 在 2015/05/04 更新過狀態(ctime)
# 為了要讓資料輸出比較好看,所以鳥哥將三個指令同時依序執行,三個指令中間用分號 (;) 隔開即可。

看到了嗎?在預設的情況下,ls 顯示出來的是該檔案的 mtime ,也就是這個檔案的內容上次被更動的時間。 至於鳥哥的系統是在 5 月 4 號的時候安裝的,因此,這個檔案被產生導致狀態被更動的時間就回溯到那個時間點了(ctime)! 而還記得剛剛我們使用的範例當中,有使用到man_db.conf這個檔案啊,所以啊,他的 atime 就會變成剛剛使用的時間了!

檔案的時間是很重要的,因為,如果檔案的時間誤判的話,可能會造成某些程式無法順利的運作。 OK!那麼萬一我發現了一個檔案來自未來,該如何讓該檔案的時間變成『現在』的時刻呢? 很簡單啊!就用『touch』這個指令即可!

Tips鳥哥的圖示 嘿嘿!不要懷疑系統時間會『來自未來』喔!很多時候會有這個問題的!舉例來說在安裝過後系統時間可能會被改變! 因為台灣時區在國際標準時間『格林威治時間, GMT』的右邊,所以會比較早看到陽光,也就是說,台灣時間比GMT時間快了八小時! 如果安裝行為不當,我們的系統可能會有八小時快轉,你的檔案就有可能來自八小時後了。

至於某些情況下,由於BIOS的設定錯誤,導致系統時間跑到未來時間,並且你又建立了某些檔案。 等你將時間改回正確的時間時,該檔案不就變成來自未來了?^_^

[root@study ~]# touch [-acdmt] 檔案
選項與參數:
-a  :僅修訂 access time;
-c  :僅修改檔案的時間,若該檔案不存在則不建立新檔案;
-d  :後面可以接欲修訂的日期而不用目前的日期,也可以使用 --date="日期或時間"
-m  :僅修改 mtime ;
-t  :後面可以接欲修訂的時間而不用目前的時間,格式為[YYYYMMDDhhmm]

範例一:新建一個空的檔案並觀察時間
[dmtsai@study ~]# cd /tmp
[dmtsai@study tmp]# touch testtouch
[dmtsai@study tmp]# ls -l testtouch
-rw-rw-r--. 1 dmtsai dmtsai 0 Jun 16 00:45 testtouch
# 注意到,這個檔案的大小是 0 呢!在預設的狀態下,如果 touch 後面有接檔案,
# 則該檔案的三個時間 (atime/ctime/mtime) 都會更新為目前的時間。若該檔案不存在,
# 則會主動的建立一個新的空的檔案喔!例如上面這個例子!

範例二:將 ~/.bashrc 複製成為 bashrc,假設複製完全的屬性,檢查其日期
[dmtsai@study tmp]# cp -a ~/.bashrc bashrc
[dmtsai@study tmp]# date; ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
Tue Jun 16 00:49:24 CST 2015                         <==這是目前的時間
-rw-r--r--. 1 dmtsai dmtsai 231 Mar  6 06:06 bashrc  <==這是 mtime
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 15 23:44 bashrc  <==這是 atime
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 16 00:47 bashrc  <==這是 ctime

在上面這個案例當中我們使用了『ll』這個指令(兩個英文L的小寫),這個指令其實就是『ls -l』的意思, ll本身不存在,是被『做出來』的一個命令別名。相關的命令別名我們會在bash章節當中詳談的,這裡先知道ll="ls -l"即可。 至於分號『 ; 』則代表連續指令的下達啦!你可以在一行指令當中寫入多重指令, 這些指令可以『依序』執行。由上面的指令我們會知道ll那一行有三個指令被下達在同一行中。

至於執行的結果當中,我們可以發現資料的內容與屬性是被複製過來的,因此檔案內容時間(mtime)與原本檔案相同。 但是由於這個檔案是剛剛被建立的,因此狀態(ctime)就變成現在的時間啦!那如果你想要變更這個檔案的時間呢?可以這樣做:

範例三:修改案例二的 bashrc 檔案,將日期調整為兩天前
[dmtsai@study tmp]# touch -d "2 days ago" bashrc
[dmtsai@study tmp]# date; ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
Tue Jun 16 00:51:52 CST 2015
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 14 00:51 bashrc
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 14 00:51 bashrc
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 16 00:51 bashrc
# 跟上個範例比較看看,本來是 16 日變成 14 日了 (atime/mtime)~不過, ctime 並沒有跟著改變喔!

範例四:將上個範例的 bashrc 日期改為 2014/06/15 2:02
[dmtsai@study tmp]# touch -t 201406150202 bashrc
[dmtsai@study tmp]# date; ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
Tue Jun 16 00:54:07 CST 2015
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 15  2014 bashrc
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 15  2014 bashrc
-rw-r--r--. 1 dmtsai dmtsai 231 Jun 16 00:54 bashrc
# 注意看看,日期在 atime 與 mtime 都改變了,但是 ctime 則是記錄目前的時間!

透過 touch 這個指令,我們可以輕易的修訂檔案的日期與時間。並且也可以建立一個空的檔案喔! 不過,要注意的是,即使我們複製一個檔案時,複製所有的屬性,但也沒有辦法複製 ctime 這個屬性的。 ctime 可以記錄這個檔案最近的狀態 (status) 被改變的時間。無論如何,還是要告知大家, 我們平時看的檔案屬性中,比較重要的還是屬於那個 mtime 啊!我們關心的常常是這個檔案的『內容』 是什麼時候被更動的說~瞭乎?

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

  • 建立一個空的檔案;
  • 將某個檔案日期修訂為目前 (mtime 與 atime)

6.4 檔案與目錄的預設權限與隱藏權限

第五章、Linux檔案權限的內容我們可以知道一個檔案有若干個屬性, 包括讀寫執行(r, w, x)等基本權限,及是否為目錄 (d) 與檔案 (-) 或者是連結檔 (l) 等等的屬性! 要修改屬性的方法在前面也約略提過了(chgrp, chown, chmod) ,本小節會再加強補充一下!

除了基本r, w, x權限外,在Linux傳統的Ext2/Ext3/Ext4檔案系統下,我們還可以設定其他的系統隱藏屬性, 這部份可使用 chattr 來設定,而以 lsattr 來查看,最重要的屬性就是可以設定其不可修改的特性!讓連檔案的擁有者都不能進行修改! 這個屬性可是相當重要的,尤其是在安全機制上面 (security)!比較可惜的是,在 CentOS 7.x 當中利用 xfs 作為預設檔案系統, 但是 xfs 就沒有支援所有的 chattr 的參數了!僅有部份參數還有支援而已!

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

例題:
你的系統有個一般身份使用者 dmtsai,他的群組屬於 dmtsai,他的家目錄在 /home/dmtsai, 你是root,你想將你的 ~/.bashrc 複製給他,可以怎麼作?
答:
由上一章的權限概念我們可以知道 root 雖然可以將這個檔案複製給 dmtsai,不過這個檔案在 dmtsai 的家目錄中卻可能讓 dmtsai 沒有辦法讀寫(因為該檔案屬於 root 的嘛!而 dmtsai 又不能使用 chown 之故)。 此外,我們又擔心覆蓋掉 dmtsai 自己的 .bashrc 設定檔,因此,我們可以進行如下的動作喔:
複製檔案: cp ~/.bashrc ~dmtsai/bashrc
修改屬性: chown dmtsai:dmtsai ~dmtsai/bashrc

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

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

6.4.1 檔案預設權限:umask

OK!那麼現在我們知道如何建立或者是改變一個目錄或檔案的屬性了,不過, 你知道當你建立一個新的檔案或目錄時,他的預設權限會是什麼嗎?呵呵!那就與 umask 這個玩意兒有關了!那麼 umask 是在搞什麼呢?基本上, umask 就是指定 『目前使用者在建立檔案或目錄時候的權限預設值』, 那麼如何得知或設定 umask 呢?他的指定條件以底下的方式來指定:

[root@study ~]# umask
0022             <==與一般權限有關的是後面三個數字!
[root@study ~]# umask -S
u=rwx,g=rx,o=rx

查閱的方式有兩種,一種可以直接輸入 umask ,就可以看到數字型態的權限設定分數, 一種則是加入 -S (Symbolic) 這個選項,就會以符號類型的方式來顯示出權限了! 奇怪的是,怎麼 umask 會有四組數字啊?不是只有三組嗎?是沒錯啦。 第一組是特殊權限用的,我們先不要理他,所以先看後面三組即可。

在預設權限的屬性上,目錄與檔案是不一樣的。從第五章我們知道 x 權限對於目錄是非常重要的! 但是一般檔案的建立則不應該有執行的權限,因為一般檔案通常是用在於資料的記錄嘛!當然不需要執行的權限了。 因此,預設的情況如下:

  • 若使用者建立為『檔案』則預設『沒有可執行( x )權限』,亦即只有 rw 這兩個項目,也就是最大為 666 分,預設權限如下:
    -rw-rw-rw-

  • 若使用者建立為『目錄』,則由於 x 與是否可以進入此目錄有關,因此預設為所有權限均開放,亦即為 777 分,預設權限如下:
    drwxrwxrwx

要注意的是,umask 的分數指的是『該預設值需要減掉的權限!』因為 r、w、x 分別是 4、2、1 分,所以囉!也就是說,當要拿掉能寫的權限,就是輸入 2 分,而如果要拿掉能讀的權限,也就是 4 分,那麼要拿掉讀與寫的權限,也就是 6 分,而要拿掉執行與寫入的權限,也就是 3 分,這樣瞭解嗎?請問你, 5 分是什麼?呵呵! 就是讀與執行的權限啦!

如果以上面的例子來說明的話,因為 umask 為 022 ,所以 user 並沒有被拿掉任何權限,不過 group 與 others 的權限被拿掉了 2 (也就是 w 這個權限),那麼當使用者:

  • 建立檔案時:(-rw-rw-rw-) - (-----w--w-) ==> -rw-r--r--
  • 建立目錄時:(drwxrwxrwx) - (d----w--w-) ==> drwxr-xr-x
不相信嗎?我們就來測試看看吧!
[root@study ~]# umask
0022
[root@study ~]# touch test1
[root@study ~]# mkdir test2
[root@study ~]# ll -d test*
-rw-r--r--. 1 root root 0  6月 16 01:11 test1
drwxr-xr-x. 2 root root 6  6月 16 01:11 test2

呵呵!瞧見了吧!確定新建檔案的權限是沒有錯的。

  • umask的利用與重要性:專題製作

想像一個狀況,如果你跟你的同學在同一部主機裡面工作時,因為你們兩個正在進行同一個專題, 老師也幫你們兩個的帳號建立好了相同群組的狀態,並且將 /home/class/ 目錄做為你們兩個人的專題目錄。 想像一下,有沒有可能你所製作的檔案你的同學無法編輯?果真如此的話,那就傷腦筋了!

這個問題很常發生啊!舉上面的案例來看就好了,你看一下 test1 的權限是幾分? 644 呢!意思是『如果 umask 訂定為 022 ,那新建的資料只有使用者自己具有 w 的權限, 同群組的人只有 r 這個可讀的權限而已,並無法修改喔!』這樣要怎麼共同製作專題啊!您說是吧!

所以,當我們需要新建檔案給同群組的使用者共同編輯時,那麼 umask 的群組就不能拿掉 2 這個 w 的權限! 所以囉, umask 就得要是 002 之類的才可以!這樣新建的檔案才能夠是 -rw-rw-r-- 的權限模樣喔! 那麼如何設定 umask 呢?簡單的很,直接在 umask 後面輸入 002 就好了!

[root@study ~]# umask 002
[root@study ~]# touch test3
[root@study ~]# mkdir test4
[root@study ~]# ll -d test[34]   # 中括號 [ ] 代表中間有個指定的字元,而不是任意字元的意思
-rw-rw-r--. 1 root root 0  6月 16 01:12 test3
drwxrwxr-x. 2 root root 6  6月 16 01:12 test4

所以說,這個 umask 對於新建檔案與目錄的預設權限是很有關係的!這個概念可以用在任何伺服器上面, 尤其是未來在你架設檔案伺服器 (file server) ,舉例來說, SAMBA Server 或者是 FTP server 時, 都是很重要的觀念!這牽涉到你的使用者是否能夠將檔案進一步利用的問題喔!不要等閒視之!

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

Tips鳥哥的圖示 關於 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) 的說明!



6.4.2 檔案隱藏屬性

什麼?檔案還有隱藏屬性?光是那九個權限就快要瘋掉了,竟然還有隱藏屬性,真是要命~ 但是沒辦法,就是有檔案的隱藏屬性存在啊!不過,這些隱藏的屬性確實對於系統有很大的幫助的~ 尤其是在系統安全 (Security) 上面,重要的緊呢!不過要先強調的是,底下的chattr指令只能在Ext2/Ext3/Ext4的 Linux 傳統檔案系統上面完整生效, 其他的檔案系統可能就無法完整的支援這個指令了,例如 xfs 僅支援部份參數而已。底下我們就來談一談如何設定與檢查這些隱藏的屬性吧!

  • chattr (設定檔案隱藏屬性)
[root@study ~]# chattr [+-=][ASacdistu] 檔案或目錄名稱
選項與參數:
+   :增加某一個特殊參數,其他原本存在參數則不動。
-   :移除某一個特殊參數,其他原本存在參數則不動。
=   :設定一定,且僅有後面接的參數

A  :當設定了 A 這個屬性時,若你有存取此檔案(或目錄)時,他的存取時間 atime 將不會被修改,
     可避免 I/O 較慢的機器過度的存取磁碟。(目前建議使用檔案系統掛載參數處理這個項目)
S  :一般檔案是非同步寫入磁碟的(原理請參考前一章sync的說明),如果加上 S 這個屬性時,
     當你進行任何檔案的修改,該更動會『同步』寫入磁碟中。
a  :當設定 a 之後,這個檔案將只能增加資料,而不能刪除也不能修改資料,只有root 才能設定這屬性
c  :這個屬性設定之後,將會自動的將此檔案『壓縮』,在讀取的時候將會自動解壓縮,
     但是在儲存的時候,將會先進行壓縮後再儲存(看來對於大檔案似乎蠻有用的!)
d  :當 dump 程序被執行的時候,設定 d 屬性將可使該檔案(或目錄)不會被 dump 備份
i  :這個 i 可就很厲害了!他可以讓一個檔案『不能被刪除、改名、設定連結也無法寫入或新增資料!』
     對於系統安全性有相當大的助益!只有 root 能設定此屬性
s  :當檔案設定了 s 屬性時,如果這個檔案被刪除,他將會被完全的移除出這個硬碟空間,
     所以如果誤刪了,完全無法救回來了喔!
u  :與 s 相反的,當使用 u 來設定檔案時,如果該檔案被刪除了,則資料內容其實還存在磁碟中,
     可以使用來救援該檔案喔!
注意1:屬性設定常見的是 a 與 i 的設定值,而且很多設定值必須要身為 root 才能設定
注意2:xfs 檔案系統僅支援 AadiS 而已

範例:請嘗試到/tmp底下建立檔案,並加入 i 的參數,嘗試刪除看看。
[root@study ~]# cd /tmp
[root@study tmp]# touch attrtest     <==建立一個空檔案
[root@study tmp]# chattr +i attrtest <==給予 i 的屬性
[root@study tmp]# rm attrtest        <==嘗試刪除看看
rm: remove regular empty file `attrtest'? y
rm: cannot remove `attrtest': Operation not permitted
# 看到了嗎?呼呼!連 root 也沒有辦法將這個檔案刪除呢!趕緊解除設定!

範例:請將該檔案的 i 屬性取消!
[root@study tmp]# chattr -i attrtest

這個指令是很重要的,尤其是在系統的資料安全上面!由於這些屬性是隱藏的性質,所以需要以 lsattr 才能看到該屬性呦!其中,個人認為最重要的當屬 +i 與 +a 這個屬性了。+i 可以讓一個檔案無法被更動,對於需要強烈的系統安全的人來說, 真是相當的重要的!裡頭還有相當多的屬性是需要 root 才能設定的呢!

此外,如果是 log file 這種的登錄檔,就更需要 +a 這個可以增加,但是不能修改舊有的資料與刪除的參數了!怎樣?很棒吧! 未來提到登錄檔 (十八章) 的認知時,我們再來聊一聊如何設定他吧!

  • lsattr (顯示檔案隱藏屬性)
[root@study ~]# lsattr [-adR] 檔案或目錄
選項與參數:
-a :將隱藏檔的屬性也秀出來;
-d :如果接的是目錄,僅列出目錄本身的屬性而非目錄內的檔名;
-R :連同子目錄的資料也一併列出來! 

[root@study tmp]# chattr +aiS attrtest
[root@study tmp]# lsattr attrtest
--S-ia---------- attrtest

使用 chattr 設定後,可以利用 lsattr 來查閱隱藏的屬性。不過, 這兩個指令在使用上必須要特別小心,否則會造成很大的困擾。例如:某天你心情好,突然將 /etc/shadow 這個重要的密碼記錄檔案給他設定成為具有 i 的屬性,那麼過了若干天之後, 你突然要新增使用者,卻一直無法新增!別懷疑,趕快去將 i 的屬性拿掉吧!



6.4.3 檔案特殊權限: SUID, SGID, SBIT

我們前面一直提到關於檔案的重要權限,那就是 rwx 這三個讀、寫、執行的權限。 但是,眼尖的朋友們在第五章的目錄樹章節中, 一定注意到了一件事,那就是,怎麼我們的 /tmp 權限怪怪的? 還有,那個 /usr/bin/passwd 也怪怪的?怎麼回事啊?看看先:

[root@study ~]# ls -ld /tmp ; ls -l /usr/bin/passwd
drwxrwxrwt. 14 root root 4096 Jun 16 01:27 /tmp
-rwsr-xr-x. 1 root root 27832 Jun 10  2014 /usr/bin/passwd

不是應該只有 rwx 嗎?還有其他的特殊權限( s 跟 t )啊?啊.....頭又開始昏了~ @_@ 因為 s 與 t 這兩個權限的意義與系統的帳號 (第十三章)系統的程序(process, 第十六章)較為相關, 所以等到後面的章節談完後你才會比較有概念!底下的說明先看看就好,如果看不懂也沒有關係, 先知道s放在哪裡稱為SUID/SGID以及如何設定即可,等系統程序章節讀完後,再回來看看喔!

  • Set UID

當 s 這個標誌出現在檔案擁有者的 x 權限上時,例如剛剛提到的 /usr/bin/passwd 這個檔案的權限狀態:『-rwsr-xr-x』,此時就被稱為 Set UID,簡稱為 SUID 的特殊權限。 那麼SUID的權限對於一個檔案的特殊功能是什麼呢?基本上SUID有這樣的限制與功能:

  • SUID 權限僅對二進位程式(binary program)有效;
  • 執行者對於該程式需要具有 x 的可執行權限;
  • 本權限僅在執行該程式的過程中有效 (run-time);
  • 執行者將具有該程式擁有者 (owner) 的權限。

講這麼硬的東西你可能對於 SUID 還是沒有概念,沒關係,我們舉個例子來說明好了。 我們的 Linux 系統中,所有帳號的密碼都記錄在 /etc/shadow 這個檔案裡面,這個檔案的權限為:『---------- 1 root root』,意思是這個檔案僅有root可讀且僅有root可以強制寫入而已。 既然這個檔案僅有 root 可以修改,那麼鳥哥的 dmtsai 這個一般帳號使用者能否自行修改自己的密碼呢? 你可以使用你自己的帳號輸入『passwd』這個指令來看看,嘿嘿!一般使用者當然可以修改自己的密碼了!

唔!有沒有衝突啊!明明 /etc/shadow 就不能讓 dmtsai 這個一般帳戶去存取的,為什麼 dmtsai 還能夠修改這個檔案內的密碼呢? 這就是 SUID 的功能啦!藉由上述的功能說明,我們可以知道

  1. dmtsai 對於 /usr/bin/passwd 這個程式來說是具有 x 權限的,表示 dmtsai 能執行 passwd;
  2. passwd 的擁有者是 root 這個帳號;
  3. dmtsai 執行 passwd 的過程中,會『暫時』獲得 root 的權限;
  4. /etc/shadow 就可以被 dmtsai 所執行的 passwd 所修改。

但如果 dmtsai 使用 cat 去讀取 /etc/shadow 時,他能夠讀取嗎?因為 cat 不具有 SUID 的權限,所以 dmtsai 執行 『cat /etc/shadow』 時,是不能讀取 /etc/shadow 的。我們用一張示意圖來說明如下:

SUID程式執行的過程示意圖
圖6.4.1、SUID程式執行的過程示意圖

另外,SUID 僅可用在binary program 上, 不能夠用在 shell script 上面!這是因為 shell script 只是將很多的 binary 執行檔叫進來執行而已!所以 SUID 的權限部分,還是得要看 shell script 呼叫進來的程式的設定, 而不是 shell script 本身。當然,SUID 對於目錄也是無效的~這點要特別留意。

  • Set GID

當 s 標誌在檔案擁有者的 x 項目為 SUID,那 s 在群組的 x 時則稱為 Set GID, SGID 囉!是這樣沒錯!^_^。 舉例來說,你可以用底下的指令來觀察到具有 SGID 權限的檔案喔:

[root@study ~]# ls -l /usr/bin/locate
-rwx--s--x. 1 root slocate 40496 Jun 10  2014 /usr/bin/locate

與 SUID 不同的是,SGID 可以針對檔案或目錄來設定!如果是對檔案來說, SGID 有如下的功能:

  • SGID 對二進位程式有用;
  • 程式執行者對於該程式來說,需具備 x 的權限;
  • 執行者在執行的過程中將會獲得該程式群組的支援!

舉例來說,上面的 /usr/bin/locate 這個程式可以去搜尋 /var/lib/mlocate/mlocate.db 這個檔案的內容 (詳細說明會在下節講述), mlocate.db 的權限如下:

[root@study ~]# ll /usr/bin/locate /var/lib/mlocate/mlocate.db
-rwx--s--x. 1 root slocate   40496 Jun 10  2014 /usr/bin/locate
-rw-r-----. 1 root slocate 2349055 Jun 15 03:44 /var/lib/mlocate/mlocate.db

與 SUID 非常的類似,若我使用 dmtsai 這個帳號去執行 locate 時,那 dmtsai 將會取得 slocate 群組的支援, 因此就能夠去讀取 mlocate.db 啦!非常有趣吧!

除了 binary program 之外,事實上 SGID 也能夠用在目錄上,這也是非常常見的一種用途! 當一個目錄設定了 SGID 的權限後,他將具有如下的功能:

  • 使用者若對於此目錄具有 r 與 x 的權限時,該使用者能夠進入此目錄;
  • 使用者在此目錄下的有效群組(effective group)將會變成該目錄的群組;
  • 用途:若使用者在此目錄下具有 w 的權限(可以新建檔案),則使用者所建立的新檔案,該新檔案的群組與此目錄的群組相同。

SGID 對於專案開發來說是非常重要的!因為這涉及群組權限的問題,您可以參考一下本章後續情境模擬的案例,應該就能夠對於 SGID 有一些瞭解的!^_^

  • Sticky Bit

這個 Sticky Bit, SBIT 目前只針對目錄有效,對於檔案已經沒有效果了。SBIT 對於目錄的作用是:

  • 當使用者對於此目錄具有 w, x 權限,亦即具有寫入的權限時;
  • 當使用者在該目錄下建立檔案或目錄時,僅有自己與 root 才有權力刪除該檔案

換句話說:當甲這個使用者於 A 目錄是具有群組或其他人的身份,並且擁有該目錄 w 的權限, 這表示『甲使用者對該目錄內任何人建立的目錄或檔案均可進行 "刪除/更名/搬移" 等動作。』 不過,如果將 A 目錄加上了 SBIT 的權限項目時, 則甲只能夠針對自己建立的檔案或目錄進行刪除/更名/移動等動作,而無法刪除他人的檔案。

舉例來說,我們的 /tmp 本身的權限是『drwxrwxrwt』, 在這樣的權限內容下,任何人都可以在 /tmp 內新增、修改檔案,但僅有該檔案/目錄建立者與 root 能夠刪除自己的目錄或檔案。這個特性也是挺重要的啊!你可以這樣做個簡單的測試:

  1. 以 root 登入系統,並且進入 /tmp 當中;
  2. touch test,並且更改 test 權限成為 777 ;
  3. 以一般使用者登入,並進入 /tmp;
  4. 嘗試刪除 test 這個檔案!

由於 SUID/SGID/SBIT 牽涉到程序的概念,因此再次強調,這部份的資料在您讀完第十六章關於程序方面的知識後,要再次的回來瞧瞧喔! 目前,你先有個簡單的基礎概念就好了!文末的參考資料也建議閱讀一番喔!

  • SUID/SGID/SBIT 權限設定

前面介紹過 SUID 與 SGID 的功能,那麼如何設定檔案使成為具有 SUID 與 SGID 的權限呢? 這就需要第五章的數字更改權限的方法了! 現在你應該已經知道數字型態更改權限的方式為『三個數字』的組合, 那麼如果在這三個數字之前再加上一個數字的話,最前面的那個數字就代表這幾個權限了!

  • 4 為 SUID
  • 2 為 SGID
  • 1 為 SBIT

假設要將一個檔案權限改為『-rwsr-xr-x』時,由於 s 在使用者權限中,所以是 SUID ,因此, 在原先的 755 之前還要加上 4 ,也就是:『 chmod 4755 filename 』來設定!此外,還有大 S 與大 T 的產生喔!參考底下的範例啦!

Tips鳥哥的圖示 注意:底下的範例只是練習而已,所以鳥哥使用同一個檔案來設定,你必須瞭解 SUID 不是用在目錄上,而 SBIT 不是用在檔案上的喔!

[root@study ~]# cd /tmp
[root@study tmp]# touch test                  <==建立一個測試用空檔
[root@study tmp]# chmod 4755 test; ls -l test <==加入具有 SUID 的權限
-rwsr-xr-x 1 root root 0 Jun 16 02:53 test
[root@study tmp]# chmod 6755 test; ls -l test <==加入具有 SUID/SGID 的權限
-rwsr-sr-x 1 root root 0 Jun 16 02:53 test
[root@study tmp]# chmod 1755 test; ls -l test <==加入 SBIT 的功能!
-rwxr-xr-t 1 root root 0 Jun 16 02:53 test
[root@study tmp]# chmod 7666 test; ls -l test <==具有空的 SUID/SGID 權限
-rwSrwSrwT 1 root root 0 Jun 16 02:53 test

最後一個例子就要特別小心啦!怎麼會出現大寫的 S 與 T 呢?不都是小寫的嗎? 因為 s 與 t 都是取代 x 這個權限的,但是你有沒有發現阿,我們是下達 7666 喔!也就是說, user, group 以及 others 都沒有 x 這個可執行的標誌( 因為 666 嘛 ),所以,這個 S, T 代表的就是『空的』啦!怎麼說? SUID 是表示『該檔案在執行的時候,具有檔案擁有者的權限』,但是檔案 擁有者都無法執行了,哪裡來的權限給其他人使用?當然就是空的啦! ^_^

而除了數字法之外,妳也可以透過符號法來處理喔!其中 SUID 為 u+s ,而 SGID 為 g+s ,SBIT 則是 o+t 囉!來看看如下的範例:

# 設定權限成為 -rws--x--x 的模樣:
[root@study tmp]# chmod u=rwxs,go=x test; ls -l test
-rws--x--x 1 root root 0 Jun 16 02:53 test

# 承上,加上 SGID 與 SBIT 在上述的檔案權限中!
[root@study tmp]# chmod g+s,o+t test; ls -l test
-rws--s--t 1 root root 0 Jun 16 02:53 test


6.4.4 觀察檔案類型:file

如果你想要知道某個檔案的基本資料,例如是屬於 ASCII 或者是 data 檔案,或者是 binary , 且其中有沒有使用到動態函式庫 (share library) 等等的資訊,就可以利用 file 這個指令來檢閱喔!舉例來說:

[root@study ~]# file ~/.bashrc
/root/.bashrc: ASCII text  <==告訴我們是 ASCII 的純文字檔啊!
[root@study ~]# file /usr/bin/passwd
/usr/bin/passwd: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically 
linked (uses shared libs), for GNU/Linux 2.6.32, 
BuildID[sha1]=0xbf35571e607e317bf107b9bcf65199988d0ed5ab, stripped
# 執行檔的資料可就多的不得了!包括這個檔案的 suid 權限、相容於 Intel x86-64 等級的硬體平台
# 使用的是 Linux 核心 2.6.32 的動態函式庫連結等等。
[root@study ~]# file /var/lib/mlocate/mlocate.db
/var/lib/mlocate/mlocate.db: data  <== 這是 data 檔案!

透過這個指令,我們可以簡單的先判斷這個檔案的格式為何喔!包括未來你也可以用來判斷使用 tar 包裹時,該 tarball 檔案是使用哪一種壓縮功能哩!


6.5 指令與檔案的搜尋

檔案的搜尋可就厲害了!因為我們常常需要知道那個檔案放在哪裡,才能夠對該檔案進行一些修改或維護等動作。 有些時候某些軟體設定檔的檔名是不變的,但是各 distribution 放置的目錄則不同。 此時就得要利用一些搜尋指令將該設定檔的完整檔名捉出來,這樣才能修改嘛!您說是吧!^_^

6.5.1 指令檔名的搜尋

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

  • which (尋找『執行檔』)
[root@study ~]# which [-a] command
選項或參數:
-a :將所有由 PATH 目錄中可以找到的指令均列出,而不止第一個被找到的指令名稱

範例一:搜尋 ifconfig 這個指令的完整檔名
[root@study ~]# which ifconfig
/sbin/ifconfig 

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

範例三:請找出 history 這個指令的完整檔名
[root@study ~]# which history
/usr/bin/which: no history in (/usr/local/sbin:/usr/local/bin:/sbin:/bin:
/usr/sbin:/usr/bin:/root/bin)

[root@study ~]# history --help
-bash: history: --: invalid option
history: usage: history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg 
# 瞎密?怎麼可能沒有 history ,我明明就能夠用 root 執行 history 的啊!

這個指令是根據『PATH』這個環境變數所規範的路徑,去搜尋『執行檔』的檔名~ 所以,重點是找出『執行檔』而已!且 which 後面接的是『完整檔名』喔!若加上 -a 選項,則可以列出所有的可以找到的同名執行檔,而非僅顯示第一個而已!

最後一個範例最有趣,怎麼 history 這個常用的指令竟然找不到啊!為什麼呢?這是因為 history 是『bash 內建的指令』啦! 但是 which 預設是找 PATH 內所規範的目錄,所以當然一定找不到的啊(有 bash 就有 history!)!那怎辦?沒關係!我們可以透過 type 這個指令喔! 關於 type 的用法我們將在 第十章的 bash 再來談!



6.5.2 檔案檔名的搜尋

再來談一談怎麼搜尋檔案吧!在 Linux 底下也有相當優異的搜尋指令呦!通常 find 不很常用的!因為速度慢之外, 也很操硬碟!一般我們都是先使用 whereis 或者是 locate 來檢查,如果真的找不到了,才以 find 來搜尋呦! 為什麼呢?因為 whereis 只找系統中某些特定目錄底下的檔案而已,locate 則是利用資料庫來搜尋檔名,當然兩者就相當的快速, 並且沒有實際的搜尋硬碟內的檔案系統狀態,比較省時間啦!

  • whereis (由一些特定的目錄中尋找檔案檔名)
[root@study ~]# whereis [-bmsu] 檔案或目錄名
選項與參數:
-l    :可以列出 whereis 會去查詢的幾個主要目錄而已
-b    :只找 binary 格式的檔案
-m    :只找在說明檔 manual 路徑下的檔案
-s    :只找 source 來源檔案
-u    :搜尋不在上述三個項目當中的其他特殊檔案

範例一:請找出 ifconfig 這個檔名
[root@study ~]# whereis ifconfig 
ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz

範例二:只找出跟 passwd 有關的『說明文件』檔名(man page)
[root@study ~]# whereis passwd     # 全部的檔名通通列出來!
passwd: /usr/bin/passwd /etc/passwd /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
[root@study ~]# whereis -m passwd  # 只有在 man 裡面的檔名才抓出來!
passwd: /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz

等一下我們會提到 find 這個搜尋指令, find 是很強大的搜尋指令,但時間花用的很大!(因為 find 是直接搜尋硬碟,為如果你的硬碟比較老舊的話,嘿嘿!有的等!) 這個時候 whereis 就相當的好用了!另外, whereis 可以加入選項來找尋相關的資料,例如,如果你是要找可執行檔 (binary) 那麼加上 -b 就可以啦! 如果不加任何選項的話,那麼就將所有的資料列出來囉!

那麼 whereis 到底是使用什麼咚咚呢?為何搜尋的速度會比 find 快這麼多? 其實那也沒有什麼,只是因為 whereis 只找幾個特定的目錄而已~並沒有全系統去查詢之故。所以說,whereis 主要是針對 /bin /sbin 底下的執行檔, 以及 /usr/share/man 底下的 man page 檔案,跟幾個比較特定的目錄來處理而已。所以速度當然快的多!不過,就有某些檔案是你找不到的啦! 想要知道 whereis 到底查了多少目錄?可以使用 whereis -l 來確認一下即可!

  • locate / updatedb
[root@study ~]# locate [-ir] keyword
選項與參數:
-i  :忽略大小寫的差異;
-c  :不輸出檔名,僅計算找到的檔案數量
-l  :僅輸出幾行的意思,例如輸出五行則是 -l 5
-S  :輸出 locate 所使用的資料庫檔案的相關資訊,包括該資料庫紀錄的檔案/目錄數量等
-r  :後面可接正規表示法的顯示方式

範例一:找出系統中所有與 passwd 相關的檔名,且只列出 5 個
[root@study ~]# locate -l 5 passwd
/etc/passwd
/etc/passwd-
/etc/pam.d/passwd
/etc/security/opasswd
/usr/bin/gpasswd

範例二:列出 locate 查詢所使用的資料庫檔案之檔名與各資料數量
[root@study ~]# 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 7.x 是每天更新資料庫一次!),所以當你新建立起來的檔案, 卻還在資料庫更新之前搜尋該檔案,那麼 locate 會告訴你『找不到!』呵呵!因為必須要更新資料庫呀!

那能否手動更新資料庫哪?當然可以啊!更新 locate 資料庫的方法非常簡單,直接輸入『 updatedb 』就可以了! updatedb 指令會去讀取 /etc/updatedb.conf 這個設定檔的設定,然後再去硬碟裡面進行搜尋檔名的動作, 最後就更新整個資料庫檔案囉!因為 updatedb 會去搜尋硬碟,所以當你執行 updatedb 時,可能會等待數分鐘的時間喔!

  • updatedb:根據 /etc/updatedb.conf 的設定去搜尋系統硬碟內的檔名,並更新 /var/lib/mlocate 內的資料庫檔案;
  • locate:依據 /var/lib/mlocate 內的資料庫記載,找出使用者輸入的關鍵字檔名。
  • find
[root@study ~]# 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@study ~]# find / -mtime 0
# 那個 0 是重點!0 代表目前的時間,所以,從現在開始到 24 小時前,
# 有變動過內容的檔案都會被列出來!那如果是三天前的 24 小時內?
# find / -mtime 3 有變動過的檔案都被列出的意思!

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

時間參數真是挺有意思的!我們現在知道 atime, ctime 與 mtime 的意義,如果你想要找出一天內被更動過的檔案名稱, 可以使用上述範例一的作法。但如果我想要找出『4天內被更動過的檔案檔名』呢?那可以使用『 find /var -mtime -4 』。那如果是『4天前的那一天』就用『 find /var -mtime 4 』。有沒有加上『+, -』差別很大喔!我們可以用簡單的圖示來說明一下:

find 相關的時間參數意義
圖6.5.1、find 相關的時間參數意義

圖中最右邊為目前的時間,越往左邊則代表越早之前的時間軸啦。由圖 6.5.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 底下屬於 dmtsai 的檔案
[root@study ~]# find /home -user dmtsai
# 這個東西也很有用的~當我們要找出任何一個使用者在系統當中的所有檔案時,
# 就可以利用這個指令將屬於某個使用者的所有檔案都找出來喔!

範例四:搜尋系統中不屬於任何人的檔案
[root@study ~]# 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@study ~]# find / -name passwd

範例五-1:找出檔名包含了 passwd 這個關鍵字的檔案
[root@study ~]# find / -name "*passwd*"
# 利用這個 -name 可以搜尋檔名啊!預設是完整檔名,如果想要找關鍵字,
# 可以使用類似 * 的任意字元來處理

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

範例七:搜尋檔案當中含有 SGID 或 SUID 或 SBIT 的屬性
[root@study ~]# find / -perm /7000 
# 所謂的 7000 就是 ---s--s--t ,那麼只要含有 s 或 t 的就列出,所以當然要使用 /7000,
# 使用 -7000 表示要同時含有 ---s--s--t 的所有三個權限。而只需要任意一個,就是 /7000 ~瞭乎?

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

[root@study ~]# find /usr/bin /usr/sbin -perm /6000

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

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

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

範例九:找出系統中,大於 1MB 的檔案
[root@study ~]# find / -size +1M

find 的特殊功能就是能夠進行額外的動作(action)。我們將範例八的例子以圖解來說明如下:

find 相關的額外動作
圖6.5.2、find 相關的額外動作

該範例中特殊的地方有 {} 以及 \; 還有 -exec 這個關鍵字,這些東西的意義為:

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

透過圖 6.5.2 你應該就比較容易瞭解 -exec 到 \; 之間的意義了吧!

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

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

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


6.6 極重要的複習!權限與指令間的關係

我們知道權限對於使用者帳號來說是非常重要的,因為他可以限制使用者能不能讀取/建立/刪除/修改檔案或目錄! 在這一章我們介紹了很多檔案系統的管理指令,第五章則介紹了很多檔案權限的意義。在這個小節當中, 我們就將這兩者結合起來,說明一下什麼指令在什麼樣的權限下才能夠運作吧!^_^

一、讓使用者能進入某目錄成為『可工作目錄』的基本權限為何:

  • 可使用的指令:例如 cd 等變換工作目錄的指令;
  • 目錄所需權限:使用者對這個目錄至少需要具有 x 的權限
  • 額外需求:如果使用者想要在這個目錄內利用 ls 查閱檔名,則使用者對此目錄還需要 r 的權限。

二、使用者在某個目錄內讀取一個檔案的基本權限為何?

  • 可使用的指令:例如本章談到的 cat, more, less等等
  • 目錄所需權限:使用者對這個目錄至少需要具有 x 權限;
  • 檔案所需權限:使用者對檔案至少需要具有 r 的權限才行!

三、讓使用者可以修改一個檔案的基本權限為何?

  • 可使用的指令:例如 nano 或未來要介紹的 vi 編輯器等;
  • 目錄所需權限:使用者在該檔案所在的目錄至少要有 x 權限;
  • 檔案所需權限:使用者對該檔案至少要有 r, w 權限

四、讓一個使用者可以建立一個檔案的基本權限為何?

  • 目錄所需權限:使用者在該目錄要具有 w,x 的權限,重點在 w 啦!

五、讓使用者進入某目錄並執行該目錄下的某個指令之基本權限為何?

  • 目錄所需權限:使用者在該目錄至少要有 x 的權限;
  • 檔案所需權限:使用者在該檔案至少需要有 x 的權限
例題:
讓一個使用者 dmtsai 能夠進行『cp /dir1/file1 /dir2』的指令時,請說明 dir1, file1, dir2 的最小所需權限為何?
答:
執行 cp 時, dmtsai 要『能夠讀取來源檔,並且寫入目標檔!』所以應參考上述第二點與第四點的說明! 因此各檔案/目錄的最小權限應該是:
  • dir1 :至少需要有 x 權限;
  • file1:至少需要有 r 權限;
  • dir2 :至少需要有 w, x 權限。

例題:
有一個檔案全名為 /home/student/www/index.html ,各相關檔案/目錄的權限如下:
drwxr-xr-x 23 root    root    4096 Sep 22 12:09 /
drwxr-xr-x  6 root    root    4096 Sep 29 02:21 /home
drwx------  6 student student 4096 Sep 29 02:23 /home/student
drwxr-xr-x  6 student student 4096 Sep 29 02:24 /home/student/www
-rwxr--r--  6 student student  369 Sep 29 02:27 /home/student/www/index.html
請問 vbird 這個帳號(不屬於student群組)能否讀取 index.html 這個檔案呢?
答:
雖然 www 與 index.html 是可以讓 vbird 讀取的權限,但是因為目錄結構是由根目錄一層一層讀取的, 因此 vbird 可進入 /home 但是卻不可進入 /home/student/ ,既然連進入 /home/student 都不許了, 當然就讀不到 index.html 了!所以答案是『vbird不會讀取到 index.html 的內容』喔!

那要如何修改權限呢?其實只要將 /home/student 的權限修改為最小 711 ,或者直接給予 755 就可以囉! 這可是很重要的概念喔!

6.7 重點回顧

  • 絕對路徑:『一定由根目錄 / 寫起』;相對路徑:『不由 / 寫起,而是由相對當前目錄寫起』
  • 特殊目錄有:., .., -, ~, ~account需要注意;
  • 與目錄相關的指令有:cd, mkdir, rmdir, pwd 等重要指令;
  • rmdir 僅能刪除空目錄,要刪除非空目錄需使用『 rm -r 』指令;
  • 使用者能使用的指令是依據 PATH 變數所規定的目錄去搜尋的;
  • ls 可以檢視檔案的屬性,尤其 -d, -a, -l 等選項特別重要!
  • 檔案的複製、刪除、移動可以分別使用:cp, rm , mv等指令來操作;
  • 檢查檔案的內容(讀檔)可使用的指令包括有:cat, tac, nl, more, less, head, tail, od 等
  • cat -n 與 nl 均可顯示行號,但預設的情況下,空白行會不會編號並不相同;
  • touch 的目的在修改檔案的時間參數,但亦可用來建立空檔案;
  • 一個檔案記錄的時間參數有三種,分別是 access time(atime), status time (ctime), modification time(mtime),ls 預設顯示的是 mtime。
  • 除了傳統的rwx權限之外,在Ext2/Ext3/Ext4/xfs檔案系統中,還可以使用chattr與lsattr設定及觀察隱藏屬性。 常見的包括只能新增資料的 +a 與完全不能更動檔案的 +i 屬性。
  • 新建檔案/目錄時,新檔案的預設權限使用 umask 來規範。預設目錄完全權限為drwxrwxrwx, 檔案則為-rw-rw-rw-。
  • 檔案具有SUID的特殊權限時,代表當使用者執行此一binary程式時,在執行過程中使用者會暫時具有程式擁有者的權限
  • 目錄具有SGID的特殊權限時,代表使用者在這個目錄底下新建的檔案之群組都會與該目錄的群組名稱相同。
  • 目錄具有SBIT的特殊權限時,代表在該目錄下使用者建立的檔案只有自己與root能夠刪除!
  • 觀察檔案的類型可以使用 file 指令來觀察;
  • 搜尋指令的完整檔名可用 which 或 type ,這兩個指令都是透過 PATH 變數來搜尋檔名;
  • 搜尋檔案的完整檔名可以使用 whereis 找特定目錄或 locate 到資料庫去搜尋,而不實際搜尋檔案系統;
  • 利用 find 可以加入許多選項來直接查詢檔案系統,以獲得自己想要知道的檔名。

6.8 本章習題:

( 要看答案請將滑鼠移動到『答:』底下的空白處,按下左鍵圈選空白處即可察看 )
情境模擬題一:假設系統中有兩個帳號,分別是 alex 與 arod ,這兩個人除了自己群組之外還共同支援一個名為 project 的群組。假設這兩個用戶需要共同擁有 /srv/ahome/ 目錄的開發權,且該目錄不許其他人進入查閱。 請問該目錄的權限設定應為何?請先以傳統權限說明,再以 SGID 的功能解析。
  • 目標:瞭解到為何專案開發時,目錄最好需要設定 SGID 的權限!
  • 前提:多個帳號支援同一群組,且共同擁有目錄的使用權!
  • 需求:需要使用 root 的身份來進行 chmod, chgrp 等幫用戶設定好他們的開發環境才行! 這也是管理員的重要任務之一!
首先我們得要先製作出這兩個帳號的相關資料,帳號/群組的管理在後續我們會介紹, 您這裡先照著底下的指令來製作即可:
[root@study ~]# groupadd project        <==增加新的群組
[root@study ~]# useradd -G project alex <==建立 alex 帳號,且支援 project
[root@study ~]# useradd -G project arod <==建立 arod 帳號,且支援 project
[root@study ~]# id alex                 <==查閱 alex 帳號的屬性
uid=1001(alex) gid=1002(alex) groups=1002(alex),1001(project) <==確實有支援!
[root@study ~]# id arod
uid=1002(arod) gid=1003(arod) groups=1003(arod),1001(project) <==確實有支援!
然後開始來解決我們所需要的環境吧!
  1. 首先建立所需要開發的專案目錄:
    [root@study ~]# mkdir /srv/ahome
    [root@study ~]# ll -d /srv/ahome
    drwxr-xr-x. 2 root root 6 Jun 17 00:22 /srv/ahome
    
  2. 從上面的輸出結果可發現 alex 與 arod 都不能在該目錄內建立檔案,因此需要進行權限與屬性的修改。 由於其他人均不可進入此目錄,因此該目錄的群組應為project,權限應為770才合理。
    [root@study ~]# chgrp project /srv/ahome
    [root@study ~]# chmod 770 /srv/ahome
    [root@study ~]# ll -d /srv/ahome
    drwxrwx---. 2 root project 6 Jun 17 00:22 /srv/ahome
    # 從上面的權限結果來看,由於 alex/arod 均支援 project,因此似乎沒問題了!
    
  3. 實際分別以兩個使用者來測試看看,情況會是如何?先用 alex 建立檔案,然後用 arod 去處理看看。
    [root@study ~]# su - alex       <==先切換身份成為 alex 來處理
    [alex@www ~]$ cd /srv/ahome   <==切換到群組的工作目錄去
    [alex@www ahome]$ touch abcd  <==建立一個空的檔案出來!
    [alex@www ahome]$ exit        <==離開 alex 的身份
    
    [root@study ~]# su - arod
    [arod@www ~]$ cd /srv/ahome
    [arod@www ahome]$ ll abcd
    -rw-rw-r--. 1 alex alex 0 Jun 17 00:23 abcd
    # 仔細看一下上面的檔案,由於群組是 alex ,arod並不支援!
    # 因此對於 abcd 這個檔案來說, arod 應該只是其他人,只有 r 的權限而已啊!
    [arod@www ahome]$ exit
    
    由上面的結果我們可以知道,若單純使用傳統的 rwx 而已,則對剛剛 alex 建立的 abcd 這個檔案來說, arod 可以刪除他,但是卻不能編輯他!這不是我們要的樣子啊!趕緊來重新規劃一下。

  4. 加入 SGID 的權限在裡面,並進行測試看看:
    [root@study ~]# chmod 2770 /srv/ahome
    [root@study ~]# ll -d /srv/ahome
    drwxrws---. 2 root project 17 Jun 17 00:23 /srv/ahome
    
    測試:使用 alex 去建立一個檔案,並且查閱檔案權限看看:
    [root@study ~]# su - alex
    [alex@www ~]$ cd /srv/ahome
    [alex@www ahome]$ touch 1234
    [alex@www ahome]$ ll 1234
    -rw-rw-r--. 1 alex project 0 Jun 17 00:25 1234
    # 沒錯!這才是我們要的樣子!現在 alex, arod 建立的新檔案所屬群組都是 project,
    # 由於兩人均屬於此群組,加上 umask 都是 002,這樣兩人才可以互相修改對方的檔案!
    
    所以最終的結果顯示,此目錄的權限最好是『2770』,所屬檔案擁有者屬於root即可,至於群組必須要為兩人共同支援的project 這個群組才行!

簡答題部分:
  • 什麼是絕對路徑與相對路徑
    絕對路徑的寫法為由 / 開始寫,至於相對路徑則不由 / 開始寫!此外,相對路徑為相對於目前工作目錄的路徑!
  • 如何更改一個目錄的名稱?例如由 /home/test 變為 /home/test2
    mv /home/test /home/test2
  • PATH 這個環境變數的意義?
    這個是用來指定執行檔執行的時候,指令搜尋的目錄路徑。
  • umask 有什麼用處與優點?
    umask 可以拿掉一些權限,因此,適當的定義 umask 有助於系統的安全, 因為他可以用來建立預設的目錄或檔案的權限。
  • 當一個使用者的 umask 分別為 033 與 044 他所建立的檔案與目錄的權限為何?
    在 umask 為 033 時,則預設是拿掉 group 與 other 的 w(2)x(1) 權限,因此權限就成為『檔案 -rw-r--r-- , 目錄 drwxr--r-- 』而當 umask 044 時,則拿掉 r 的屬性,因此就成為『檔案 -rw--w--w-,目錄 drwx-wx-wx』
  • 什麼是 SUID ?
    當一個指令具有 SUID 的功能時,則:
    • SUID 權限僅對二進位程式(binary program)有效;
    • 執行者對於該程式需要具有 x 的可執行權限;
    • 本權限僅在執行該程式的過程中有效 (run-time);
    • 執行者將具有該程式擁有者 (owner) 的權限。
  • 當我要查詢 /usr/bin/passwd 這個檔案的一些屬性時(1)傳統權限;(2)檔案類型與(3)檔案的隱藏屬性,可以使用什麼指令來查詢?
    ls -al
    file
    lsattr
  • 嘗試用 find 找出目前 linux 系統中,所有具有 SUID 的檔案有哪些?
    find / -perm +4000 -print
  • 找出 /etc 底下,檔案大小介於 50K 到 60K 之間的檔案,並且將權限完整的列出 (ls -l):
    find /etc -size +50k -a -size -60k -exec ls -l {} \;
    注意到 -a ,那個 -a 是 and 的意思,為符合兩者才算成功
  • 找出 /etc 底下,檔案容量大於 50K 且檔案所屬人不是 root 的檔名,且將權限完整的列出 (ls -l);
    find /etc -size +50k -a ! -user root -exec ls -ld {} \;
    find /etc -size +50k -a ! -user root -type f -exec ls -l {} \;
    上面兩式均可!注意到 ! ,那個 ! 代表的是反向選擇,亦即『不是後面的項目』之意!
  • 找出 /etc 底下,容量大於 1500K 以及容量等於 0 的檔案:
    find /etc -size +1500k -o -size 0
    相對於 -a ,那個 -o 就是或 (or) 的意思囉!

6.9 參考資料與延伸閱讀

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- 』的刪除方法!
2008/09/23:將針對FC4版寫的資料移到此處
2008/09/29:加入權限與指令的關係一節,並新增情境模擬題目喔!大家幫忙除錯一下!
2009/08/18:加入符號法的方式來處理 SUID/SGID/SBIT 囉!
2009/08/26:感謝網友告知習題部分,找出 /etc 底下容量大於 50k 的那題,應使用 -type f 或 ls -ld 來避免目錄內重複顯示!
2015/06/04:將舊的基於 CentOS 5 的文章移動到此處
2015/06/24:感謝網友『学习日记博客』的告知,whereis 以前一直寫錯了!這次給它訂正一下!感謝!
2015/08/25:感謝網友『学习日记博客』的告知,cp 的參數內, -a 不僅代表 -pdr !因為有 SELinux 的影響的關係!

2002/03/13以來統計人數
計數器
>>
HOME
PrePage
NextPage
   http://linux.vbird.org is designed by VBird during 2001-2015.