Linux 檔案系統架構
理論上所有 Linux 發布版都應該要遵守 Linux 檔案系統的標準(Filesystem Hierarchy Standard, FHS),但不同版本可能會有些許差異,大致結構如下:
根目錄(/)底下的目錄
目錄名稱 | 說明 | 例 |
---|---|---|
/bin |
放一些一般使用者可以操作的指令。連結到 /usr/bin | kill、cp.. |
/sbin |
放置系統管理員可以操作的指令。連結到 /usr/sbin | |
/boot |
系統開機相關的一些載入檔 | |
/etc |
系統設定檔案 | |
/home |
主要是一般帳戶的家目錄 | |
/root |
系統管理者的家目錄 | |
/lib , /lib64 |
主要為系統函式庫和核心函式庫,若是 64 位元則放在 /lib64。連結到 /usr/lib, /usr/lib64 | |
/proc |
整個系統的運作資訊 | |
/sys |
與 /proc 類似,但主要針對硬體相關參數 | |
/usr |
全名為 unix software resource 縮寫,放置系統相關軟體、服務(注意不是 user 的縮寫) | X-Window |
/var |
記載著各種系統上的變數的地方 | |
/tmp |
全名為 temporary,放置暫存檔案(雜七雜八的東西) | |
/media |
放置隨插即用的裝置慣用目錄 | |
/mnt |
為管理員、使用者手動掛上(mount)的目錄 | |
/opt |
全名為 optional,通常為第三方廠商放置軟體處 | |
/srv |
通常是放置開發的服務(service),如:網站服務 www 等 | |
/vmlinuz |
系統核心檔案 | |
lost+found |
系統檢查結果 | |
/run |
系統進行服務軟體運作管理處 | |
/cdrom |
光碟機裡的資料被掛上來的地方 | |
/dosc |
開機時把 dos 檔案系統掛上來的地方 | |
/dev |
放置 device 裝置檔案,鍵盤滑鼠等 |
基本指令
1. 資料夾與檔案處理
mkdir
建立資料夾
結構:
mkdir [OPTION] DIR
參數:
- -p:多層目錄同時創建
範例:
1 | # 新增 myDir 資料夾 |
rm
remove - 刪除檔案或資料夾
結構:
rm [OPTION] FILE
參數:
- -r:刪除資料夾
- -f:強制刪除
範例:
1 | # 刪除檔案 |
ls
list - 列出資料夾下內容
結構:
ls [OPTION] DIR
參數:
- -l:列出詳細檔案資訊 (權限、日期等)
- -a:也列出隱藏檔案
- -R:遞迴,也列出子資料夾內的所有檔案及資料夾內容
範例:
1 | # 只列出檔名 |
cd
change directory - 切換工作目錄
範例:
1 | # 進入 myDir 資料夾 |
pwd
print working directory - 列出當前工作目錄
範例:
1 | pwd |
cp
copy - 複製資料夾或檔案
結構:
cp [OPTION] SOURCE DEST 【 cp -參數 來源檔(或目錄) 目的檔(或目錄) 】
參數:
- -r:針對目錄下檔案做遞歸複製(白話:整個目錄下每一個檔案複製到你想要的位置)
- -p:將檔案本身屬性(權限、所有者、時間)同時複製過去(一般用於備份居多)
- -f:拷貝時若相同檔名的檔案直接複蓋不提出警告(強制複製)
- -i:如果要複製過去的位置已經有相同檔案,會在覆蓋前詢問是否持續進行
- -s:複製成符號連結檔(symbolic link)(白話:複製成捷徑檔)
範例:
1 | # 將 a.txt 複製成一份 b.txt (若操作的目標在當下目錄內,也可以不加./) |
補充說明:像是特殊權限檔案 (/etc/shadow),密碼檔、設定檔 …等,需要加上 -a 或 -p 參數,才能完整複製檔案。如果複製過程希望有進度條功能,建議改用 scp 或 rsync 指令
mv
move - 移動或重命名資料夾或檔案
結構:
mv [OPTION] SOURCE DEST 【 mv -參數 來源檔(或目錄) 目的檔(或目錄) 】
參數:
- -b:移動之前先做備份
- -v:做完移動之後顯示所做的移動情形
- -f:強迫性移動,不會詢問使用者是否確認
1 | # 將當下目錄 a.txt 改名成 b.txt (若操作的目標在當下目錄內,也可以不加./) |
rm
remove - 刪除檔案或資料夾
結構:
rm [OPTION] FILE
參數:
- -r:刪除資料夾
- -f:強制刪除
範例:
1 | # 刪除檔案 |
find
在指定資料夾與其子資料夾搜尋檔案,輸出符合條件資料之路徑
參數:
- -name:指定檔案(目錄)名稱
- -iname:不區分大小寫
範例:
基礎
1 | # 查詢當前目錄下的檔名為 a.txt 的檔案 (. 可省略,不給值預設就是查詢當下目錄) |
「或」邏輯運算符
1 | # 在 HOME 目錄下尋找 html 和 js 檔案 |
指定檔案類型
1 | # 指定只要搜尋「檔案」名稱 |
檔案大小
1 | # 找尋所有檔案大小大於 50MB 的檔案 (不加上 -name 代表搜尋全部檔案) |
時間
1 | # 尋找超過 7 天沒有被存取或修改過的檔案 (判斷檔案存取時間) |
使用者
1 | 尋找特定使用者的檔案 |
exec 執行
指令解釋:尋找名字為 a.txt 的檔案,透過 -exec 指令將輸出結果 (a.txt 檔案路徑),丟入 cat 執行,印出檔案內文本。
1 | find ~ -type f -iname 'a.txt' -print -exec cat {} \; |
- ~ (相當於 $HOME) 目錄
- 指令最後一個分號前一定要加上反斜線
- 加上 –print 是為了讓被刪除的檔案檔名一併顯示在畫面上,這個參數可以省略
- 使用 –exec 會讓查詢到的每一個檔案路徑代入 {} 位置,一個檔案會執行一遍 cat 命令
1 | # 補充,上面的 exec 範例也可以用原生的 xargs 指令達成相同效果 |
實用範例:
1 | # 在當前目錄中,找出檔案大小在 10 MB 以上的 mp3 檔案,並刪除。 |
diff
以逐行的方式,比較文本文件的異同處。如果指定要比較目錄,則 diff 會比較目錄中相同文件名的文件,但不會比較其中子目錄
參數:
- -c:(上下文模式) 顯示差異處的前後內文,並標出差異處
- -u:(Git diff 模式)
- -y:(並排模式)
- -b:不比較空白字元
- -B:不比較空白行數
- -w:忽略全部的空白和 tab
- -i:忽略大小寫
- -l:忽略指定字串的差異
- -q:僅顯示是否有差異,不顯示其餘訊息
用法參考:
2. 文本處理
cat
將檔案內容印在終端機上。
參數:
- -n:由 1 開始對所有輸出的行數編號
- -b:和 n 類似,不過空白行不編號
- -s:當遇到兩行以上空白行,就合為一行空白行
- -E:在每行結束點顯示 $ 符號
範例:
1 | # 將 a.txt 內容加上行號,並覆寫 b.txt 內容 |
實用範例:
1 | # 清空 a.txt 內容 |
echo
印出一行文本
範例:
1 | # output: It is a string |
範例 2:
以下程式碼儲存為 test.sh 檔案
1 | !/bin/sh |
執行 sh test.sh
,後輸入字串,該字串將成為 shell 變數 ($name)
1 | [root@www ~]# sh test.sh |
實用範例:
1 | # 以 "It is a test" 字串覆蓋 a.txt 內容 |
grep
用關鍵字找尋檔案
結構:
grep [OPTION] 內容關鍵字 [檔名條件] [目錄或檔案路徑]
參數:
- -r:遞歸搜尋,搜尋指定目錄還有其子目錄內容
- -a:不忽略二進位資料
- -A<顯示行數>:除了符合關鍵字的行內容,額外多顯示該行”之後”的內容(多的行數就是你所指定的數字)
- -B<顯示行數>:同 -A,但是是多顯示”之前”的內容
- -C<顯示行數>:同 -A -B,前後的內容都顯示,顯示的行數就是指定的數量
- -v:反向搜尋
- -E:將關鍵字用正則表達式使用
- -i:忽略大小寫
- -n:顯示行數
範例:
1 | # 在當前目錄搜尋檔名結尾為 file 且內容含有 hello 字串的目標,並將該檔案符合該字串的行內容輸出 |
正則:
1 | # a 開頭 |
wc
利用 wc 指令我們可以計算檔案的位元組數,字數,或者列數,如果不指定檔案名,或者所造成的檔案稱為’-‘,則 wc 指令會從標準輸入設備讀取資料。
參數:
- -l:只顯示行數
- -w:只顯示字數 (單字)
- -c:只顯示 Bytes 數
範例:
1 | # a.txt |
1 | wc a.txt |
sort
預設將檔案內容依照 ASCII 碼的次序排列,再輸到終端
參數:
- -b:忽略美航前面開始出的空格字元
- -d:排序時,處理英文字母、數字及空格字符外,忽略其他的字符
- -f:排序時,將小寫字母視為大寫字母
- -o<輸出檔案 >:將排序後的結果存入指定的檔案。
- r:以相反的順序來排序。
範例:
1 | $ cat testfile #testfile文件原有排序 |
使用 sort 指令
1 | sort testfile |
輸出
1 | Hello 95 |
3. 系統管理
Linux 系統對於檔案設有三種權限,分別為讀 Read
、寫 Write
、執行 eXecute
,另外不同的角色能擁有的檔案權限都不同,角色則分別有使用者 user
、群組 group
、其他 others
三種,輸入 ls -l 指令後可以觀察到所有檔案和目錄的權限資訊。想深入學習可以閱讀鳥哥的第五章 - Linux 的檔案權限與目錄配置。
圖片來源: 鳥哥
chmod
Linux 的檔案角色權限分為三級:使用者 user
、群組 group
、其他 others
,利用該指令可以控制檔案如何被他人利用。
參數:
- u (使用者)、g (群組)、o (其他)、a (全部)
- + (增加權限)、- (取消權限)、= (唯一設定權限)
- r (可讀取)、w (可寫入)、x (可執行)、X (只有該檔案是個子目錄或該檔案已經被設定過為可執行)
其他參數:
- -f:若該檔案權限無法被更改也不要顯示錯誤訊息
- -v:顯示權限變更的詳細資料
- -R:遞歸,對該目錄下所有檔案與子目錄進行相同權限變更
範例:
1 | # 將檔案 a.txt 設定為所有人皆可讀取 |
另外權限也可以用數字來表示,語法為:
1 | chmod abc file |
a,b,c 各為一個數字,分別代表 User、Group、others 的權限
權重表:
| Read | Write | eXecute |
| ——– | ——– | ——– |
| 4 | 2 | 1 |
若要 rwx 權限,則 4+2+1=7,也就是 7 代表著最高權限,若要 rw 權限,則 4+2=6.. 以此類推
範例:
1 | chmod a=rwx a.txt |
chown
Linux/Unix 是多人多工作業系統,所有的檔案皆有擁有者。利用 chown 將指定檔案的擁有者改為指定的使用者或組,使用者可以是使用者名或者使用者 ID;組可以是組名或者組 ID;檔案是以空格分開的要改變權限的檔案。
一般來說,這個指令只有是由系統管理者(root)所使用,一般使用者沒有權限可以改變別人的檔案擁有者,也沒有權限把自己的檔案擁有者改設為別人。只有系統管理者(root)才有這樣的權限。
參數:
- -f:若該檔案權限無法被更改也不要顯示錯誤訊息
- -v:顯示權限變更的詳細資料
- -R:遞歸,對該目錄下所有檔案與子目錄進行相同權限變更
使用 chown 指令前可以先透過 ls -l
來查看或是確認欲更改檔案的擁有者及群組。
圖片來源: 鳥哥
範例:
將 a.txt 的擁有者改為 usera
1 | sudo chown usera a.txt |
將 a.txt 的群組改為 groupa,第一個參數須以冒號開頭,代表更改群組。
1 | sudo chown :groupa a.txt |
同時更改使用者及群組
1 | sudo chown usera:groupa a.txt |
預設情況下,使用 chown 指令後並不會出現任訊息(除非出現錯誤),若要讓 chown 明確顯示更改結果,要加上 -v 參數
1 | sudo chown -v usera a.txt |
若不想輸出任何錯誤訊息,可以加上 -f
1 | sudo chown -f usera a.txt |
如果要一次修改某個目錄下所有檔案與子目錄的擁有者與群組,可以使用 chown 加上 -R 參數來處理
1 | sudo chown -R usera:groupa myDir |
如果想要把某檔案的擁有者與群組改成和另一個檔案一樣
1 | # 將 myDir 的擁有者與群組改成和 refDir 一樣 |
實用範例
1 | # 找出目前目錄下所有的 *.c 檔,並將這些檔案的擁有者與群組改為 myuser:mygroup |
su
switch user - 切換到其他 Linux 用戶,但是不切換環境變數,除 root 外,需要輸入該使用者密碼,所有使用者皆有權限使用該指令。
參數:
- -m -p:執行 su 時,不改變環境變數
- -c
:變更帳號後執行後面接著的指令,再切回原來的使用者 - -s:指定要執行的 shell,預設值為 /etc/passwd 內該使用者的 shell
- - -l:加了這個參數後,就好像重新 login 為該使用者一樣,大部分環境變數都是以該使用者為主,並且工作目錄也會改變,如果沒有指定使用者,預設為 root
範例:
取得 root 權限。執行 su 並輸入密碼後,可以取得 root (最高) 權限。
1 | su |
忘記 root 密碼解決方式:在 Ubuntu 下第一次使用 root 時會提示要求你輸入密碼,你可能會發現自己根本沒有設置過密碼。輸入指令
sudo passwd root
,終端會提示你 Enter new UNIX password 和 Reentry new UNIX password,建立一個 root 帳戶就可以了,看到 password updated successfully 就表示成功了。
不過要注意,在這種情況下,雖然使用者帳號的 user id 變成 0 (root 的 user id),但其他的環境變數並沒有跟著改變。
若是單純要以 root 權限做一些更改檔案的小變動,用這個指令就夠了。但是如果需要進行·以較複雜的系統管理,牽涉到許多 root 帳號的環境變數 (例如 PATH
或 MAIL
)時,就要改用下面的方式
1 | su - |
這個指令相當於用 root 重新登入一樣,進入一個完整的 shell 環境。
使用以上兩種方式,都會開啟一個新的 shell 環境,完成工作後需要輸入 exit
才會離開該環境。若你的操作並不複雜可以使用 -c 參數,後面接著你想執行的 shell 指令,如此的話不會進入新的 shell 環境,而是使用 root 權限執行完該指令後,回到原先的帳號 shell 環境。
1 | su - -c 'env | grep root' |
除了讓一般使用者可以使用 root 權限以外,也可以取得其他非 root 帳號的權限
1 | su -l dylan.liu237 |
該指令可以取得 dylan.liu237
這個帳號的權限,而這裡的密碼就必須輸入這個帳號的密碼。如果是以 root 身份執行則不需要輸入密碼。
sudo
sudo 類似 su 指令,也是用來取得 root 或是其他帳號權限,但他在使用上是輸入自己的密碼,而不是 root 或其他帳號的密碼,使用上更方便。
Ubuntu Linux 系統預設在安裝時基於安全考量,並不會啟用 root 帳號,無法用 root 直接登入系統,所有的系統管理動作都是透過 sudo 來取得 root 權限。
參數:
- -l:印出自己(執行 sudo 的使用者)的權限
- -V:列出 sudo 的版本資訊
- -u
:以另一個 user 身份執行指令 - -s:執行環境變數中的 SHELL 所指定的 shell,或 /etc/passwd 裡所指定的 shell
sudo 用起來和 su -c
很類似,執行完指令後會自動離開 root 的 shell 環境
1 | # 查看環境變數,因為使用 sudo 指令,輸出的變數為 root 的環境變數 |
如果要查看 dylan.liu237
這個帳號的環境變數,可以切換到該帳號權限,再做查看
1 | sudo -u dylan.liu237 env | grep dylan.liu237 |
也可以取得特定群組的權限,例如取的 adm 全組權限後,看系統記錄檔
1 | sudo -g adm view /ver/log/syslog |
實用範例:
透過這個指令可以利用 sudo 不需要輸入密碼的特性,開啟一個 root 的 shell 環境,很常在 Ubuntu Linux 中使用。
1 | sudo su - |
補充:
sudo 可以不需要 root 密碼情況下取得 root 權限,在正常情況下當然不可能讓任何使用者都可以使用 root 權限,他是依據 /etc/sudoers
設定檔來控管的。只有在這個檔案中有被特別設定的使用者才可以使用 sudo 指令。
編輯
/etc/sudoers
時,建議使用visudo
指令來開啟 vi 編輯器進行編輯,系統將在編輯完成時檢查語法是否正確,避免錯誤語法造成 sudo 無法使用。
使用指令:sudo visudo -f /etc/sudoers
/etc/sudoers` 對個別使用者的設定與法格式如下
1 | 帳號名稱 來源主機=(可切換帳號) 可執行命令 |
帳號名稱 | 來源主機 | 可切換帳號 | 可執行命令 |
---|---|---|---|
可以使用 sudo 的帳號名稱 |
限制使用者從特定網路主機連線時,才能使用 sudo 指令,可用來防止入侵者從不明的主機登入攻擊。若指定為 ALL 則代表不限制來源主機。 |
可以取得哪些帳號的權限。若指定為 ALL 則代表可以取得任何帳號的權限。 |
在取得特殊權限後,可以執行的指令。若指定為 ALL 則代表可以執行任何令。 |
個別使用者設定:
若要讓 dylan.liu237
帳號可以使用 sudo 執行所有指令,需在 /etc/sudoers 加入此行
1 | dylan.liu237 ALL=(ALL) ALL |
允許使用者使用 sudo 指令取的 root 權限,就等於讓使用者成為系統管理者,並不建議這樣做。
理想的情況,可以建立一個使用者專門管理其他使用者密碼的,可以把它定義為一個密碼管理員帳號,可以透過以下方式實現
1 | accmgr ALL=(root) /usr/bin/passwd |
上面這樣的寫法有一個問題,就是該使用者也可以更改 root 的密碼,如果 root 帳號可以被更改,代表整個該帳號可以透過更改 root 密碼來取得系統的最高管理權限,可以加上以下設定防止
1 | accmgr ALL=(root) !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root |
以上設定加上了更多限制 - !/usr/bin/passwd
: 不許該帳號使用 /usr/bin/passwd 指令 - /usr/bin/passwd [A-Za-z]
: 只允許更改一般使用者密碼 - !/usr/bin/passwd root
: 禁止更改 root 密碼
群組設定:
對特定群組底下帳號一次開放權限,可以直接對特定群組進行定義
1 | %群組名稱 來源主機=(可切換帳號) 可執行的指令 |
群組設定和使用者設定只差在群組名稱前的 % 前綴,其他欄位皆相同。如果要讓 groupa 群組下的所有使用者都可以用 sudo 指令,可以這樣設定
1 | %groupa ALL=(ALL) ALL |
不需輸入密碼:
想讓特定群組或使用者可以在不須輸入密碼的情況下,直接使用 sudo,可以加入 NOPASSWD
設定
沒有加入
NOPASSWD
設定,預設五分鐘後必須再次輸入密碼
1 | // 使用者 |
使用 Alias:
有些情況 /etc/sudoers
的設定比較複雜,例如同時設定多個使用者或是多個允許指令,可以用 alias 做到類似變數的概念來管理
1 | User_Alias MYACC = acc1, acc2, acc3 |
passwd
更改使用者密碼
passwd 指令可以變更使用者密碼,對於非 root 使用者而言,執行 passwd 後需輸入現行密碼後才可以更改密碼;如果是 root 則不需要,並可以更改所有使用者的密碼,包含 root 自己。
/etc/passwd
目錄儲存的是作業系統使用者訊息,該檔案為所有使用者可見。/etc/shadow
被稱為/etc/passwd
的影子檔案。它們之間的內容是互補的。shadow 內容包括使用者及被加密的密碼以及其它/etc/passwd
不能包括的訊息,比如使用者的有效期限等。
#
參數:
- -S:顯示密碼狀態資訊
- -aS:顯示所有帳號訊息
- -d:移除使用者密碼
- -e:設定密碼過期狀態
- -l:鎖定使用者密碼
- -u:解除鎖定使用者密碼
- -n
:設定每隔多久才能變更一次密碼 - -x
:設定每隔多久需要更換一次密碼 - -w
:過期前幾天給予使用者變更密碼警告 - -i
:設定寬限期,在過期後幾天使用者還是可以照常登入,過期後帳號即無法登入
範例:
修改自己的密碼,需要輸入現行密碼(root 修改自己的密碼也是一樣的指令,但是不需輸入密碼)
1 | passwd |
root 使用者更改其他使用者密碼,不需輸入現行密碼
1 | sudo passwd dylan.liu237 |
顯示密碼狀態資訊
1 | # 查看自己的密碼資訊 |
印出結果
1 | dylan.liu237 L 07/17/2020 0 99999 7 -1 |
輸出七個欄位,對應的資訊如下
- 帳號名稱
- 密碼狀態,狀態包含鎖定密碼(L)、無密碼(NP)與可用密碼(P。
- 上次修改密碼的時間。
- 密碼最短使用期限(minimum password age),單位為天。
- 密碼最長使用期限(maximum password age),單位為天。
- 密碼過期前警告期間(password warning period),單位為天。
- 密碼過期後可使用的期間(password inactivity period),單位為天。
顯示所有帳號密碼資訊 (root 權限)
1 | sudo passwd -aS |
移除使用者密碼
1 | sudo passwd -d dylan.liu237 |
變更密碼過期狀態。有時候因為某些原因,例如重新設定密碼後,會希望使用者立刻更改自己的密碼,這時候可以使用 -e 參數
1 | sudo passwd -e dylan.liu237 |
1 | passwd: password expiry information changed. |
接著檢查狀態資訊
1 | sudo passwd -S dylan.liu237 |
1 | dylan.liu237 P 01/01/1970 0 99999 7 -1 |
這時候如果使用者使用 SSH 登入的話,系統就會強制更新密碼
1 | ssh dylan.liu237@34.80.206.16 |
1 | *** System restart required *** |
鎖定使用者密碼。使用參數 -l
可以鎖定使用者密碼
1 | sudo passwd -l dylan.liu237 |
檢查使用者狀態
1 | sudo passwd -S dylan.liu237 |
1 | dylan.liu237 L 09/01/2020 0 99999 7 -1 |
在鎖定之後,系統會在 /etc/shadow
的密碼欄位之前加上 !
,在這個情況下該使用者無法更新自己的密碼
1 | dylan.liu237:!$6$aihNuUv/$c9jjnkmLa376aJ08gYXITIje8KECL25NMdVVGLOk4O4RVYEP5BrDEcTSAfAyjpV7wSABq7P89fUH.5b9cMrTN/:18506:0:99999:7::: |
解除鎖定可以使用 -u
參數
1 | sudo passwd -u dylan.liu237 |
設定密碼期限,至少每隔三天才可以變更一次密碼,設置為 0 代表可以任意變更密碼
1 | sudo passwd -n 3 dylan.liu237 |
設定密碼有效期限,每 30 天需要更換一次密碼
1 | sudo passwd -x 30 dylan.liu237 |
密碼過期前 7 天警告
1 | sudo passwd -w 7 dylan.liu237 |
當使用者密碼過期後,會有一段寬限期(inactivity period),過了以後就無法登入,可以透過 -i
參數設定該時間
1 | sudo passwd -i 10 dylan.liu237 |
4.其他
man
查詢指令說明
1 | # 查詢 ls 指令說明 |
history
列出歷史指令
1 | history |
快捷鍵
常用
Ctrl + C
中斷目前畫面上操作 (中斷前景程序 process)
Ctrl + D
離開 (等同 exit 指令 + Enter)
Ctrl + Z
將目前畫面上操作切到背景 (不中斷操作)
Ctrl + L
清理畫面 (等同 clear 指令)
Ctrl + R
根據關鍵字查詢過往輸入的 Linux 指令
移動光標
Ctrl + A
移到行首
Ctrl + E
移到行尾
Ctrl + XX
在命令行尾和光標間切換
刪除字
Ctrl + W
刪除光標前的一個單字,這樣就不用每次都要按折 delete 一個一個字刪除了
Ctrl + K
刪除光標後所有字,搭配 Ctrl + A 可以刪除整行
Ctrl + U
刪除光標前所有字,搭配 Ctrl + E 可以刪除整行
⌥ + 左右箭頭 (MAC)
以單字為單位前後切換光標