在 Linux 中,不像 Microsoft Windows 一樣有多個磁碟根目錄,所有的檔案或目錄都是位於系統 根目錄 (/
) 下。沒有其它目錄會與根目錄平行。
Linux 的目錄結構可以看成一棵樹,最上層為 /
,所有目錄或檔案都是在該項目之下。在 /
下會有基本的子目錄用來存放特定類別的項目,關於 /
之下的子目錄有其參考標準,該標準稱為 檔案系統階層標準, Filesystem Hierarchy Standard (FHS) ,是由 Linux 基金會進行維護。
Linux 目錄結構 |
---|
以下就常用的目錄進行說明。
完整位置 | 主要用途 |
---|---|
/boot/ | Linux 核心檔案存放的位置,也放置開機所需要的設定檔案 |
/etc/ | 作業系統、應用程式與服務設定檔放置的位置 |
/bin/ | 放置一般的可執行檔,大部份是會使用到的指令,連結到 /usr/bin/ 目錄 |
/sbin/ | 放置和系統管理有關的可執行檔,用來管理系統相關的指令,連結到 /usr/bin/ 目錄 |
/root/ | 系統管者 root 的家目錄 |
/home/ | 一般使用者的家目錄位置,每個帳號會在 /home/ 目錄中產生自己的可用目錄 |
/usr/ | Unix System Resource 之縮寫,程式安裝路徑,可以看成 Windows 的 Program Files 目錄 |
/var/ | 系統或服務產生的動態檔案,如系統記錄檔、資料庫實體檔等 |
/lib/ | 系統函式庫存放的位置 |
/lib64/ | 系統函式庫存放的位置,主要為 64 位元函式庫 |
/proc/ | 作業系統核心資訊的目錄,此目錄內容為虛擬,關機後會不見 |
/sys/ | 硬體週邊參數配置的目錄 |
/tmp/ | 暫存檔存放路徑,此目錄所有人都可以放置檔案或目錄,但只能刪除自己建立的物件 |
cd
是用來協助使用者切換到不同的工作目錄,這在大多數的作業系統是通用的。在 CentOS 中如果沒有提供目標目錄,那麼預設會回到家目錄中。
在目錄的表示方面,若是以 /
開頭表示,則通常代表為絕對路徑(從最原頭開始表示),若是省略了最開頭的 /
則代表是相對路徑,相對路徑指的是和目所在的位置相比較,若是搭配 ../
符號則代表 上一層 目錄,而 ./
代表從目前所在目錄。
大部份的 Shell 都能夠很聰明的判別要切換的目標是否為目錄,在目錄的表示上通常會以 /
做結尾,若是沒有 /
的話表示該目標為檔案,則無法使用 cd
切換。
操作範例如下:
切換到 /etc/
目錄
student$ cd /etc/
將工作目錄切換到家目錄,以下 2 種方式都可以
直接使用 cd
student$ cd
使用家目錄符號 ~
student$ cd ~
切換到上一個目錄
student$ pwd
/home/student
student$cd /etc/
student$ pwd
/etc
student$ cd -
student$ pwd
/home/student
mkdir
係指新增目錄的意思,在指令後面可以接一個或多個目錄,mkdir
就能夠把這些目錄建出來。在預設情況下,mkdir
只能建立在已經存在的目錄下,若建立多層次的目錄則要配合 -p
參數才會把中間層的目錄一併產生。
操作範例如下:
建立 lab
目錄
student$ mkdir lab/
建立 lab2/dir1/
目錄
student$ mkdir -p lab2/dir1/
rmdir
是用來刪除空目錄的工具,所以當要刪除的目錄裡面包含有其它物件(不論是目錄或檔案)則 rmdir
都會無法刪除。
使用下列方法,可以把 lab/ 目錄刪除。
student$ rmdir lab/
使用下列方法,因為 lab2/
中包含了一個子目錄,所以無法刪除。
student$ rmdir lab2/
FAIL!
若是遇到目標目錄裡面有其它物件存在時,可以使用 rm
搭配 -r
參數,此時 rm
會先把最後一層裡的物件刪除,直到完全清空後再把目標目錄刪除。
使用下列方法,可以把 lab2/
與其子目錄與檔案一併刪除。
student$ rm -r lab2/
與檔案的 mv
功能相同。
在 Linux 系統中,資源眾多且高度分散。這些資源主要以文件、目錄、和連結等多種形式存在。在這個龐大的系統中找出一個特定的目標文件,幾乎就像是大海撈針,手動瀏覽每個目錄是多麼耗時且低效。同時,Linux 指令也是一個令人頭痛的問題:它們既可以是實體文件,也可以是內建指令、別名或函式。
因此,在本章節中,我們將探討如何在 Linux 環境中有效的找出文件和指令。我們將介紹常用工具,包括 find
、which
、alias
和 type
,這些工具不僅能幫助我們迅速找到文件和目錄的確切位置,還能識別指令是以何種形式(如內建指令、別名或函式)存在。綜合這些方法,管理員將能更加精確和高效地管理 Linux 系統的各種資源。
要在大量的文件中找出特定的檔案,可以使用 find
指令來完成這個任務。通常我們會使用 find
再配合合適的參數增加尋找的準確度。
以下為常用參數列表:
參數 | 功用 |
---|---|
-mtime | +n 幾天前, -n 幾天內 |
-mmin | +n 幾分鐘前, -n 幾分鐘內 |
-type | f 檔案, d 目錄, -l 連結 |
-name | 指定標的名稱,大小寫相符 |
-iname | 指定標的名稱,不分大小寫 |
搭配上序參數,我們可以完成幾個操作時會使用到的應用。
在檔案更新的過程中,如果需要在更新前後把檔案與目錄列表出來以供差異比較,那麼可以直接使用 find
加目標路徑,它會列出所有的文件列表。
使用下列方式顯示 /etc/
下所有的文件列表:
student$ sudo find /etc/
/etc/
/etc/fstab
/etc/crypttab
/etc/mtab
/etc/resolv.conf
/etc/grub.d
/etc/grub.d/00_header
/etc/grub.d/01_users
/etc/grub.d/10_linux
/etc/grub.d/20_linux_xen
~ 略 ~
如果只要顯示檔案類型,那麼我們可以加上 -type f
參數,則只會列出 "檔案" 的項目:
student$ sudo find /etc/ -type f
/etc/fstab
/etc/crypttab
/etc/resolv.conf
/etc/grub.d/00_header
/etc/grub.d/01_users
/etc/grub.d/10_linux
/etc/grub.d/20_linux_xen
/etc/grub.d/20_ppc_terminfo
/etc/grub.d/30_os-prober
/etc/grub.d/40_custom
~ 略 ~
同理,使用 -type d
則列出 "目錄":
student$ sudofind /etc/ -type d
/etc/
/etc/grub.d
/etc/terminfo
/etc/skel
/etc/alternatives
/etc/chkconfig.d
/etc/rc.d
/etc/rc.d/init.d
/etc/rc.d/rc0.d
/etc/rc.d/rc1.d
除了檔案列型,我們有時候記得檔案的部份關鍵字,比如 network
是我們記得的檔案名稱,則可以加上不分大小寫的檔名來尋找。
透過加上 -iname
參數找出是檔案,檔名又是 network
的文件:
student$ sudo find /etc/ -type f -iname 'network'
/etc/rc.d/init.d/network
/etc/sysconfig/network
若是只記得檔名中部份名稱也沒有關係,find
支援萬用字元 (*)。假設要找出部份檔名為 network
,使用這個項功能可以找出如下的檔案:
network
為首的檔名: network*
。network
為尾巴的檔名: *network
。network
在檔案名稱中間: *network*
。透過下列方式,找出是檔案,部份檔名是 network
的文件:
student$ sudo find /etc/ -type f -iname '*network*'
/etc/rc.d/init.d/network
/etc/dbus-1/system.d/org.freedesktop.NetworkManager.conf
/etc/NetworkManager/NetworkManager.conf
/etc/networks
/etc/sysconfig/network-scripts/network-functions
/etc/sysconfig/network-scripts/network-functions-ipv6
/etc/sysconfig/network
透過 find
豐富的參數與彈性,能夠為我們找出檔案,如需查看所有的 find
可用參數,可執行:
student$ man find
檔案時間
我們在很多時候想要找出檔案是多久以前被修改,或最近幾日 (分鐘) 被修改,可以使用 -mtime
或 -mmin
來做處理,-mtime
尋找的單位為日,後者為分鐘。
要找出單位前 (如 3 日前),則參數值為 +3
,若要找出單位後(如 3 日內) 則參數值為 -3
。
透過列指令,找出在 /etc/
裡 3 日前被修改的文件:
student$ sudo find /etc/ -mtime +3
/etc/fstab
/etc/crypttab
/etc/mtab
/etc/resolv.conf
/etc/grub.d
/etc/grub.d/00_header
/etc/grub.d/01_users
/etc/grub.d/10_linux
~ 略 ~
若要找出 3 分鐘內被修改的文件,則可以使用 -mmin -3
來處理。
測試的流程如下:
建立 /etc/mytest
檔案:
student$ sutdo touch /etc/mytest
使用 find
找出該檔案
student$ sudo find /etc/ -type f -mmin -3
/etc/mytest
透過上列流程,我們可以找出特定時間修改的文件。
find
提供的參數眾多,如需更進階的使用方式,可以查看系統中有關 find
的說明手冊。
student$ find
在 Linux 環境中,當我們使用命令列輸入指令時,這些指令可能會以多種形式存在,包括實際的檔案、內建指令、函式或者別名(alias)。
環境變數與區域變數
在探索指令存放位置之前,我們要先了解 env
和 set
這兩個指令的差別。
env
: 顯示出目前的環境變數。這些變數僅對當前 shell 以及由它所啟動的程式有效,以系統登入來說,env 包含了系統登入後給與帳號的環境變數。set
: 列出所有變數和函式,包括環境變數和局部變數,當帳號登入以後,每個帳號自行的個人變數。若要查看系統環境變數,執行 env
:
student$ env
XDG_SESSION_ID=5347
HOSTNAME=localhost.localdomain
SELINUX_ROLE_REQUESTED=
TERM=xterm-256color
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.168.200 59595 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/1
USER=student
~ 以下略 ~
若要查看系統環境變數,執行 set
:
student$ set
set | head
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(2)-release'
~ 以下略 ~
我們可以透過一些方式來查看 set
與 env
的關係。
在下列的指令中,會檢查環境變數中是否有 "myname" 這個變數:
student$ env | grep myname
在預設的情況下,應該沒有任何的訊息輸出。
接下來使用相同的方式,在 set
中是否有 "myname" 變數:
student$ set | grep myname # 沒有結果
在預設的情況下,應該也會像 env
一樣沒有任何的訊息輸出。
現在我們設定一個值為 bob
,並且使用 "myname" 變數將他儲存起來:
student$ myname=bob
接著分別查看 env
與 set
是否有 "myname" 變數:
student$ set | grep myname
myname=bob
student$ env | grep myname
從上面的結果可以知道,我們使用的變數會存在 set
中,而不會存在環境變數裡。
若要將自訂變數儲存到環境變數中,則需要使用 export 方式將它成為全域的環境變數。
使用下列方式將 myname
轉為環境變數,然後再次查看:
student$ export myname
student$ env | grep myname
myname=bob
從上面的例子瞭解,除非變數被 export
為環境變數,否則 env
是看不到它的。
$PATH 變數
$PATH
是一個重要的環境變數,用於定義系統會到哪些目錄下尋找指令。當我們輸入一個指令如 ls
,系統會按照 $PATH
中的目錄順序來尋找這個指令。
root# echo $PATH
/home/student/.local/bin:/home/student/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
從上面的輸出來看,我們以冒號 (:) 做為分欄符號,其中的每個目錄錄徑就是系統尋找指令的位置,這些位置會有先後順序,如果同一指令在 2 個目錄中出現,那麼先找的就會就先執行,後面的就不會執行。
which
which
指令用於找出系統將會執行的指令文件路徑。
我們使用 which
來查看 cp
指令確切的所在位置:
student$ which cp
/usr/bin/cp
我們從上面的輸出中,得到 cp
指令的執行位置: /usr/bin/cp
。
修改 $PATH
並驗證
為了更加瞭解 $PATH 與路徑的關係,透過本小節的內容可以加以驗證。
在實做之前,請先切換成 root 身份:
student$ sudo su -
root#
接下來我們在 /opt/
目錄建立一個 hello
的檔案,內容如下:
#!/bin/bash
echo hello!
設定 hello
為可執行的權限,透過下列方式完成:
root# chmod +x /opt/hello
執行該檔案:
root# /opt/hello
hello
若執行無誤,會在畫面上顯示 "hello" 字樣。
現在我們模擬一般輸入指令的方式,在終端機上直接輸入該指令:如果嘗試直接執行 hello
,將會因為 $PATH
沒有包含 /opt
而失敗。
root# hello
-bash: hello: command not found
此時,我們把 /opt
加入到 $PATH
變數中:
root# export PATH=$PATH:/opt
然後確認 $PATH 變數有加入我們的 /opt
路徑:
root# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/opt
現在,which
和直接執行 hello
應該都會成功。
root# which hello
/opt/hello
root# hello
hello
透過這個過程可以瞭解如何在 Linux 中找出並執行特定的指令,並且知道 env
、set
和 $PATH
的工作原理及其重要性。
在大部份的情境下,我們習慣在 bash 中輸入指令並做相對應的處理,然而這些指令並不全都是系統上實際的可執行檔,有些是 bash 內建,有些是真的可執行檔,也有一些是以函式的方式存在。
我們怎麼去判別所下的指令是什麼行態呢?可以使用 type
指令來確認。
以下為一些常見的類別輸出:
函式行態
root# type which
which is a function
which ()
{
( alias;
eval ${which_declare} ) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot $@
}
別名型態
root# type ls
ls is aliased to `ls --color=auto'
Shell 內建方法
root# type cd
cd is a shell builtin
一般執行檔
root# type vi
vi is /usr/bin/vi
由上範例可以瞭解,雖然我們在 bash 執行的指令可以運作,但確有可能是對應到不用的型態,不一定都是實際存在的可執行檔。
在 bash 作業環境中,有時候執行的指令需要下多個參數,為了簡化這個流程,可以把一串常用的指令加上參數做為別名。
在系統中已經有一些別名的存在,使用下列方法可以查看目前設定的別名:
root# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde
從上面的輸出範例中,可以查看到有幾個常用的項目是別名而不是實際的指令,比方說 ll
這個別名,是由 ls -l --color=auto
所組成的。
透過下面的操作,我們可以新增一個別名為 myalias
,對應到 echo "Hello My Alias"
,做法如下:
root# alias myalias="echo 'Hello My Alias'"
接著,在命令列上輸入 myalias,會得到輸出:
root# myalias
Hello My Alias
檢查 myalias
的型別:
root# type myalias
myalias is aliased to `echo 'Hello My Alias''
查看所有 alias
項目:
root# alias
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias myalias='echo '\''Hello My Alias'\'''
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
上述輸出中,myalias
就是我們剛才新增的別名。
如要刪除已經存在的別名,可以使用 unalias
指令進行處理。
下列指令可以刪除 myalias
別名:
root# unalias myalias