iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0

目錄操作

在 Linux 中,不像 Microsoft Windows 一樣有多個磁碟根目錄,所有的檔案或目錄都是位於系統 根目錄 (/) 下。沒有其它目錄會與根目錄平行。

Linux 目錄結構

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

cd 是用來協助使用者切換到不同的工作目錄,這在大多數的作業系統是通用的。在 CentOS 中如果沒有提供目標目錄,那麼預設會回到家目錄中。

在目錄的表示方面,若是以 / 開頭表示,則通常代表為絕對路徑(從最原頭開始表示),若是省略了最開頭的 / 則代表是相對路徑,相對路徑指的是和目所在的位置相比較,若是搭配 ../ 符號則代表 上一層 目錄,而 ./ 代表從目前所在目錄。

大部份的 Shell 都能夠很聰明的判別要切換的目標是否為目錄,在目錄的表示上通常會以 / 做結尾,若是沒有 / 的話表示該目標為檔案,則無法使用 cd 切換。

操作範例如下:

  1. 切換到 /etc/ 目錄

    student$ cd /etc/
    
  2. 將工作目錄切換到家目錄,以下 2 種方式都可以

    1. 直接使用 cd

      student$ cd
      
    2. 使用家目錄符號 ~

      student$ cd ~
      
  3. 切換到上一個目錄

    student$ pwd
    /home/student
    
    student$cd /etc/
    student$ pwd
    /etc
    
    student$ cd -
    student$ pwd
    /home/student
    

mkdir

mkdir 係指新增目錄的意思,在指令後面可以接一個或多個目錄,mkdir 就能夠把這些目錄建出來。在預設情況下,mkdir 只能建立在已經存在的目錄下,若建立多層次的目錄則要配合 -p 參數才會把中間層的目錄一併產生。

操作範例如下:

  1. 建立 lab 目錄

    student$ mkdir lab/
    
  2. 建立 lab2/dir1/ 目錄

    student$ mkdir -p lab2/dir1/
    

rmdir

rmdir 是用來刪除空目錄的工具,所以當要刪除的目錄裡面包含有其它物件(不論是目錄或檔案)則 rmdir 都會無法刪除。

使用下列方法,可以把 lab/ 目錄刪除。

student$ rmdir lab/

使用下列方法,因為 lab2/ 中包含了一個子目錄,所以無法刪除。

student$ rmdir lab2/
FAIL!

rm

若是遇到目標目錄裡面有其它物件存在時,可以使用 rm 搭配 -r 參數,此時 rm 會先把最後一層裡的物件刪除,直到完全清空後再把目標目錄刪除。

使用下列方法,可以把 lab2/ 與其子目錄與檔案一併刪除。

student$ rm -r lab2/

mv

與檔案的 mv 功能相同。

文件搜尋

在 Linux 系統中,資源眾多且高度分散。這些資源主要以文件、目錄、和連結等多種形式存在。在這個龐大的系統中找出一個特定的目標文件,幾乎就像是大海撈針,手動瀏覽每個目錄是多麼耗時且低效。同時,Linux 指令也是一個令人頭痛的問題:它們既可以是實體文件,也可以是內建指令、別名或函式。

因此,在本章節中,我們將探討如何在 Linux 環境中有效的找出文件和指令。我們將介紹常用工具,包括 findwhichaliastype,這些工具不僅能幫助我們迅速找到文件和目錄的確切位置,還能識別指令是以何種形式(如內建指令、別名或函式)存在。綜合這些方法,管理員將能更加精確和高效地管理 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 來處理。

測試的流程如下:

  1. 建立 /etc/mytest 檔案:

    student$ sutdo touch /etc/mytest
    
  2. 使用 find 找出該檔案

    student$ sudo find /etc/ -type f -mmin -3
    /etc/mytest
    

透過上列流程,我們可以找出特定時間修改的文件。

find 提供的參數眾多,如需更進階的使用方式,可以查看系統中有關 find 的說明手冊。

student$ find

指令所在搜尋

在 Linux 環境中,當我們使用命令列輸入指令時,這些指令可能會以多種形式存在,包括實際的檔案、內建指令、函式或者別名(alias)。

環境變數與區域變數

在探索指令存放位置之前,我們要先了解 envset 這兩個指令的差別。

  • 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'
~ 以下略 ~

我們可以透過一些方式來查看 setenv 的關係。

在下列的指令中,會檢查環境變數中是否有 "myname" 這個變數:

student$ env | grep myname

在預設的情況下,應該沒有任何的訊息輸出。

接下來使用相同的方式,在 set 中是否有 "myname" 變數:

student$ set | grep myname  # 沒有結果

在預設的情況下,應該也會像 env 一樣沒有任何的訊息輸出。

現在我們設定一個值為 bob,並且使用 "myname" 變數將他儲存起來:

student$ myname=bob

接著分別查看 envset 是否有 "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 中找出並執行特定的指令,並且知道 envset$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

上一篇
Day 4: 檔案操作
下一篇
Day 6: vi/vim 文字編輯器
系列文
Linux 升華:初學者的探索到專家的洞察30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言