第三章 使用 shell
本章介紹的 Linux shell 稱為 Bash shell,其全稱為 Bourne Again shell。還有其他的 shell,例如在 BSD UNIX 使用者中流行的 C shell (csh),以及在 UNIX System V 使用者中非常流行的 Korn shell (ksh),Ubuntu 預設啟動 Dash shell (速度比 Bash 快),還有 Tcsh shell (一種改進的 C shell) 和 Ash shell (與 Bourne shell 非常相似)。
3.1 shell 和 終端機視窗
- 使用 終端機視窗 (Terminal 窗口)
透過執行的 GUI,可以打開一個終端機模擬程式 (有時也稱為 終端機視窗),從而啟動一個 shell。
大部分系統透過 Ctrl+Shift+T 快速鍵打開,Fedora 可在程式中尋找,或者按 alt+F2 後輸入 gnome-terminal。
- 使用虛擬主控台
大多數有 GUI 的 Linux 系統在啟動時通常會執行多個虛擬主控台,虛擬主控台除了可以打開 GUI 之外,還可以打開多個 shell 工作階段。
透過 Ctrl+Shift+F1~F6 可切換虛擬主控台。以 Fedora 為例,tty1 為 gdm (登入螢幕),tty2 為第一個桌面,tty3 為第二個桌面 (純文字),以此類推。
- 命令提示字元
對於一般使用者來說,預設的提示字元是一個簡單的錢字號。
$
對於 root 使用者來說,預設的提示字元是一個井字號 (有時也稱為 number sign 或 hash tag)。
#
生動形象地說明了美國本源在英國
3.2 選擇 shell
使用 who 命令即可顯示當前登入的使用者名稱,登入的虛擬主控台以及登入的時間。
使用 grep username /etc/passwd 命令,在輸出的最後可看到預設使用的 shell。
可以透過輸入命令以切換 shell,例如 ksh、tcsh、csh、sh、dash 或其他 shell (假設已經安裝了這些 shell)。
學習 Bash shell 不僅是因為它是大多數安裝中預設的 shell,也是因為它是大多數 Linux 認證考試中所使用的 shell。
3.3 執行命令
雖然只需要透過輸入命令名稱就可以執行許多命令,但更常見的做法是在命令之後輸入更多內容,從而改變其行為。在命令之後輸入的字元和單字稱為選項和參數。
3.3.1 了解命令語法
- 大多數命令都有一個或多個用來改變命令行為的選項。
一般選項由單個字母構成,並在前面添加一個連字號 -,然而為了每次使用多個選項,也可以將多個單字母選項組合在一起,或者在每個選項前面都使用一個連字號。
一些命令的選項由一個完整的單字組成,一般需要在單字前使用雙連字號 --。例如,為了使用 help 這個選項,需要輸入 --help,如果是 -help 將被解釋為 -h、-e、-l、-p 這四個選項。儘管有些命令不遵守雙連字號約定,但大多數命令還是要在單字選項前使用雙連字號。
- 此外,大多數命令還可在輸入某些選項後或者整個命令列結尾處接受參數。
參數是一個額外的資訊區塊,比如檔名、目錄、使用者名稱、裝置或其他用來告訴命令如何執行的資訊。通常,在命令列中可以使用任意數量的參數,只要數量不超過單個命令列所允許的總字母數即可。
有時,一個參數與一個選項相關聯,此時參數必須跟在選項之後。如果使用的是單字母選項,那麼參數通常在一個空白之後。而對於全單字選項,參數跟在一個等號 = 之後。
例如:
| |
選項的含義是建立 (c) 一個名為 backup.tar 的檔案 (f),其中包含 /home/yexca 目錄的全部檔案,並且在備份檔案建立完畢 (v) 後顯示詳細資訊。因為 backup.tar 是 f 選項的一個參數,所以 backup.tar 必須跟在選項之後。
| |
–hide 選項告訴 ls 命令不要顯示名為 Desktop 的檔案或目錄,注意選項與參數之間沒有空白。
- 還可以嘗試其他的命令:
uname 命令顯示正在執行的系統類型,添加了 -a 選項後還可以查看主機名稱及核心版本。
當登入到一個 Linux 系統時,Linux 會認定您具有特定的身份,其中包括使用者名稱、群組名稱、使用者 ID 和群組 ID。此外,Linux 還會追蹤登入工作階段,從而了解登入的時間、閒置的時間以及登入的地點等。可透過 id 命令查看身份相關資訊。
啟用了 SELinux (Security Enhanced Linux) 的 Linux 發行版本都在
id輸出的末尾顯示了額外資訊,例如:context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
SELinux 提供了一種可以緊緊鎖定 Linux 系統安全性的方法。
透過 who -uH 可添加關於閒置時間和程序 ID 資訊 (u),以及要求列印標頭 (H)。
閒置 (IDLE) 表示在沒有任何命令輸入的情況下 shell 保持打開狀態的時間長度。程序號碼 (PID) 表示使用者登入 shell 的程序 ID。而備註 (COMMENT) 則表示使用者用來進行登入操作的遠端電腦名稱 (前提是使用者使用了網路上的另一台電腦進行登入),或者本地 X Display 的名稱 (前提是使用者正在使用一個終端機視窗),比如 :0.0。
3.3.2 查找命令
為了找到所輸入的命令,shell 在所謂的路徑中進行查找,對於不在路徑中的命令,可透過輸入命令位置的完整識別進行執行。
透過 echo $PATH 以查看 shell 的環境變數 PATH。
參考: Linux 下 bin 目錄 - yexca‘Blog
與其他一些作業系統不同的是,預設情況下,在搜尋路徑之前,Linux 並不會為了查找執行檔而檢查目前目錄,而是馬上開始搜尋路徑,只有在執行檔位於 PATH 環境變數或者給定了執行檔的絕對路徑或相對路徑時,才會執行目前目錄的執行檔。
並不是所有的命令都位於 PATH 變數的目錄中,一些命令內建於 shell,透過建立用來定義任何命令的別名以及選項,可以改寫另外一些命令。下面是 shell 檢查輸入命令的順序:
別名 (Alias)。由
alias命令設置的名稱,可輸入此命令以查看建立的別名。shell 保留字。shell 保留了一些單字用作特殊用途。
函式。一組能夠在目前 shell 中共同執行的命令。
內建命令。內建於 shell 中的命令,在檔案系統中沒有命令的表現形式,例如 cd、echo、exit、pwd、history (查看以前執行的命令列表)、fg (將一個背景執行的命令帶入前景)、set (設置 shell 選項) 和 type (顯示命令的位置)。
檔案系統命令。儲存在電腦檔案系統中的命令 (這些命令由 PATH 變數值表示)。
為了知道命令的出處,可以使用 type 或者 which 命令,透過使用 type -a 可顯示命令的所有已知位置。
如果一些命令不在 PATH 變數中,可使用 locate 命令嘗試查找該命令,透過使用 locate 命令可以訪問系統中任何可訪問的部分。
locate 命令會對整個檔案系統進行查找,而不僅僅是在包含了命令的目錄中查找,如果沒有找到最近添加的檔案,可以 root 使用者身份執行 updatedb 以更新 locate 資料庫。
3.4 使用命令歷史記錄重複執行命令
重複執行那些冗長、複雜且易於輸錯的命令將可以避免很多問題的出現。
3.4.1 命令列編輯
預設情況下,Bash shell 使用基於 Emacs 文字編輯器的命令列編輯。如果更喜歡使用 vi,可以將 set -o vi 添加到家目錄的 .bashrc 檔案中。
- 用來導覽命令列的按鍵:
| 按鍵 | 全稱 | 含義 |
|---|---|---|
| Ctrl+F | 向前一個字元 | 前進一個字元 |
| Ctrl+B | 向後一個字元 | 後退一個字元 |
| Alt+F | 向前一個單字 | 前進一個單字 |
| Alt+B | 向後一個單字 | 後退一個單字 |
| Ctrl+A | 命令列開頭 | 轉到目前命令列的開頭 |
| Ctrl+E | 命令列結尾 | 轉到目前命令列的結尾 |
| Ctrl+L | 清除螢幕 | 清除螢幕,並使游標停留在螢幕頂部 |
- 用來編輯命令列的按鍵:
| 按鍵 | 全稱 | 含義 |
|---|---|---|
| Ctrl+D | 刪除目前字元 | 刪除目前字元 |
| Backspace | 刪除前一個字元 | 刪除前一個字元 |
| Ctrl+T | 調換字元 | 交換目前字元和前一個字元的位置 |
| Alt+T | 調換單字 | 交換目前單字和前一個單字的位置 |
| Alt+U | 大寫單字 | 將目前單字改為大寫 |
| Alt+L | 小寫單字 | 將目前單字改為小寫 |
| Alt+C | 首字母大寫單字 | 把游標目前位置單字的頭一個字母變為大寫 |
| Ctrl+V | 插入特殊字元 | 添加一個特殊字元,例如添加 Tab |
- 用來剪下和貼上命令列中文字的按鍵:
| 按鍵 | 全稱 | 含義 |
|---|---|---|
| Ctrl+K | 剪下到行末 | 剪下游標後面的所有字元 |
| Ctrl+U | 剪下到行首 | 剪下游標前面的所有字元 |
| Ctrl+W | 剪下前一個單字 | 剪下位於目前游標之前的一個單字 |
| Alt+D | 剪下後一個單字 | 剪下位於目前游標之後的一個單字 |
| Ctrl+Y | 貼上目前文字 | 貼上最近剪下的文字 |
| Alt+Y | 貼上早期文字 | 轉回到早期剪下的文字並貼上 |
| Ctrl+C | 刪除整行 | 刪除整個命令列 |
3.4.2 命令列補全
為了減少按鍵,Bash shell 提供了多種不同的方法來補全部分輸入值。為了嘗試補全一個值,需要輸入前幾個字元並按 Tab 鍵。下面是可以透過 Bash shell 部分輸入的值:
命令、別名或函式。如果所輸入的文字以常規字元開頭,shell 將嘗試使用命令、別名或者函式名稱來補全該文字。
變數。如果所輸入的文字以錢字號
$開頭,那麼 shell 將使用來自目前 shell 的一個變數來補全文字。使用者名稱。如果所輸入的文字以波浪號
~開頭,shell 將使用一個使用者名稱補全文字。因此,~username 表示指定使用者的家目錄。主機名稱。如果所輸入的文字以 at 符號
@開頭,shell 將使用來自/etc/hosts檔案中的一個主機名稱補全文字。
如果想要添加來自其他檔案的主機名稱,只需要將 HOSTFILE 變數設置為該檔名,但該檔案必須與
/etc/hosts相同的格式。
如果所輸入的字串可以產生多種補全結果,此時可以透過雙擊 TAB 鍵列出所有可能的結果。
3.4.3 命令列重複執行
在輸入完一行命令後,該命令列會儲存到 shell 的歷史命令列表中。
透過 history 命令查看歷史命令列表,或者添加數字參數以顯示指定數量的最新命令。
透過使用驚嘆號 ! 以重複執行這些命令,此種方法將直接執行,沒有再次確認的機會。
!n — 執行命令編號。例如
!255將執行第 255 個命令。!! — 執行前一個命令。
!?string? — 執行包含字串的命令。
除了直接執行 history 外,還可重複執行特定命令並進行編輯:
| 按鍵 | 功能 | 描述 |
|---|---|---|
| 方向鍵或 Ctrl+P 與 Ctrl+N | 步驟 | 遍歷歷史命令列表的每一個命令列,直到找到所需的命令列 |
| Ctrl+R | 反向增量搜尋 | 按下後可輸入一個搜尋字串,完成反向搜尋。當輸入字串時,會出現可以執行或編輯的相匹配的命令列 |
| Ctrl+S | 向前增量搜尋 | 與上一個類似,不過是向前搜尋。並不是所有情況都可用 |
| Alt+P | 反向搜尋 | 按下後可輸入一個搜尋字串,完成反向搜尋。輸入字串並按 Enter 鍵後可看到該字串的最新命令列 |
| Alt+N | 向前搜尋 | 與上一個類似,不過是向前搜尋。並不是所有情況都可用 |
還可使用 fc 命令以使用歷史命令列表。輸入 fc 後跟著一個歷史命令列編號或一個範圍 (例如 fc 233 255),將在文字編輯器中打開這些命令 (預設為 vi),關閉編輯器後命令將 (逐個) 執行。
關閉 shell 後,歷史命令列表將儲存到家目錄的 .bash_history 檔案中,預設最多儲存 1000 條。
如果不想儲存歷史命令列表,就不要正常退出 shell,可透過
kill -9 PID關閉 shell 工作階段以不儲存歷史命令。將變數 HISTFILE 設置為 /dev/null 或保持 HISTSIZE 為空都是沒用的,只要 shell 正常退出,就會永久儲存 shell 歷史。
3.5 連接和擴充命令
shell 真正強大的功能在於能將命令的輸入和輸出重導向到其他命令或檔案中,反之亦然。
為了將命令串在一起,shell 使用了中繼字元 (metacharacter)。中繼字元是對 shell 有特殊含義的輸入字元,用於連接請求或擴充請求。
中繼字元包括管線字元 |、與號 &、分號 ;、右括號 )、左括號 (、小於號 < 和大於號 >。
3.5.1 命令之間的管線
管線字元 | 將一個命令的輸出連接到另一個命令的輸入,例如:
| |
該命令列出 /etc/passwd 檔案內容。輸出到 sort 命令以對內容排序,最後發送到 less 以顯示輸出。
3.5.2 連續命令
使用分號 ; 將多個命令隔開可在同一命令列輸入多條命令以執行連續的命令,例如:
| |
對一個很大的文件格式化,並顯示格式化所需的時間。
3.5.3 背景命令
一些命令可能需要花費很長時間才能完成,可使用與號 & 讓命令在背景執行,例如:
| |
在程序結束之前不要關閉 shell 或刪除 (kill) 該程序,否則程序將終止。
3.5.4 擴充命令
透過命令替換,可以使一條命令的標準輸出變為另一條命令的一個參數。
命令替換的兩種形式是 $(command) 和 command (注意是反引號)。
兩種形式中的命令可以包括選項、中繼字元和參數,例如:
| |
在 vi 命令執行之前完成了命令替換。首先 find 命令從 /home 目錄尋找所有檔案與目錄,然後將輸出連接到 grep 命令,將檔名中不包含 xyzzy 的過濾掉,最後使用 vi 打開所有檔案進行編輯 (每次打開一個檔案)。
注意:不要從根檔案系統開始使用 grep,否則將匹配並嘗試編輯幾千個檔案。
3.5.5 擴充算術運算式
有時可能需要將算術結果傳遞給一條命令。透過 $[expression] 或者 $((expression)),例如:
| |
輸出為 I am 65 years old。
| |
該命令列出目前目錄內容 (ls) 並執行了單字計數命令,計算出找到的檔案數量 (wc -w),然後輸出。
3.5.6 擴充變數
使用錢字號 $ 對 shell 中用來儲存資訊的變數進行擴充。當在命令列中擴充一個環境變數時,所列印的是變數的值,而不是變數名稱,例如:
| |
列印 bash 命令的詳細列表 -rwxr-xr-x. 1 root root 1390064 1月 20 2022 /usr/bin/bash
3.6 使用 shell 變數
shell 本身使用變數儲存了對使用者的 shell 工作階段非常有用的資訊。如果想要查看目前 shell 設置的所有變數,可以使用 set 命令。
其中,本地變數的一個子集被稱為環境變數,對任何透過目前 shell 打開的新 shell 都是可用的。可以使用 env 命令查看環境變數。
除了所設置的變數之外,系統檔案也會設置一些用來儲存相關資訊的變數,比如設定檔、信箱以及路徑目錄的位置。此外,這些變數還可以儲存關於 shell 提示字元、歷史命令列表的大小以及作業系統類型的相關值。如果想引用這些變數的值,需要在變數之前添加一個錢字號 $。
當啟動一個 shell 時,許多環境變數已經被設置了,下表為一些既可以在使用 Bash shell 時設置,又可以為了使用不同功能而設置的變數:
| 變數 | 描述 |
|---|---|
| BASH | 包含了 Bash 命令的完整路徑。其值通常為 /bin/bash |
| BASH_VERSION | 表示目前 Bash 命令版本的一個數字 |
| EUID | 表示目前使用者有效的使用者 ID 號碼。當啟動 shell 時,根據 /etc/passwd 檔案中的使用者項進行賦值 |
| FCEDIT | fc 命令用來編輯 history 命令的文字編輯器,預設為 vi |
| HISTFILE | 歷史命令檔案的位置,通常位於 $HOME/.bash_history |
| HISTFILESIZE | 可以儲存的歷史命令條目的數量。當達到該數量時,最早的命令將被丟棄,預設為 1000 |
| HISTCMD | 返回歷史命令列表中目前命令的數量 |
| HOME | 家目錄 |
| HOSTTYPE | 描述了 Linux 系統正在執行的電腦系統結構。對於 Intel 相容的個人電腦,其值為 i386、i486 或 i386-Linux 類似的值。而對於 AMD 64 位元電腦,其值為 x86_64 |
| 信箱檔案的位置,通常為 /var/spool/mail/$USER | |
| OLDPWD | 修改目前工作目錄之前的工作目錄 |
| OSTYPE | 用來識別目前作業系統。對於 Fedora,值為 Linux 或 Linux-gnu |
| PATH | 值為冒號 : 分隔的目錄列表,主要用來查找需要輸入的命令 |
| PPID | 目前 shell 的命令的程序 ID |
| PROMPT_COMMAND | 可以將該變數設置為一個命令名稱,以便在每次 shell 提示字元顯示之前執行該命令 |
| PS1 | 設置 shell 提示字元的值。有時命令需要額外的提示字元,可以使用變數 PS2、PS3 等進行設置 |
| PWD | 表示目前目錄 |
| RANDOM | 生成一個 0~32767 的隨機數 |
| SECONDS | 自 shell 啟動後的秒數 |
| SHLVL | 與目前 shell 工作階段相關聯的 shell 層級數。當登入到 shell 時,值為 1,每執行一次 Bash 命令後該層級數將遞增 (例如使用 su 命令或輸入 bash) |
| TMOUT | 可以為該變數設置一個數字,表示 shell 可以閒置的秒數。在秒數到達後,shell 將會退出 (登出使用者) |
3.6.1 建立和使用別名 (Alias)
使用 alias 命令可以列出所有別名以及建立別名。
| |
執行 p 命令,將執行 pwd 命令後執行 ls -CF 以列表的形式列出該目錄的內容。
如果想刪除,可使用 unalias 命令。
3.6.2 退出 shell
輸入 exit 或者按 Ctrl+D。
3.7 建立自己的 shell 環境
可以透過調整 shell 以幫助更有效地工作。
3.7.1 設定 shell
shell 的行為方式由多個設定檔所支援:
| 檔案 | 描述 |
|---|---|
| /etc/profile | 為每個使用者設置了使用者環境資訊,當首次登入時執行該檔案。該檔案還從 /etc/profile.d 目錄的設定檔中收集相關的 shell 設置。除了為諸如使用者信箱位置以及歷史檔案大小的資訊設置環境變數,還提供了路徑值 |
| /etc/bashrc | 每次打開一個 Bash shell 時都會執行該檔案,可透過每個使用者的 ~/.bashrc 檔案中的資訊改寫該檔案。設置了預設的提示字元,同時還可添加一個或多個別名 |
| ~/.bash_profile | 用來被每個使用者輸入 shell 具體用法資訊的檔案,只有當使用者登入才會執行該檔案。預設情況下,它設置一些環境變數並執行使用者的 .bashrc 檔案。該檔案是添加環境變數的絕佳位置 |
| ~/.bashrc | 包含了特定於 Bash shell 的資訊,當進行登入以及每次打開一個新 Bash shell 都會讀取該檔案。該檔案是添加別名的好地方 |
| ~/.bash_logout | 每次登出時執行該檔案,預設會清除螢幕 |
如果想更改 /etc/profile 或 /etc/bashrc 檔案,則必須是 root 使用者。一般建立 /etc/profile.d/custom.sh 檔案來添加系統全域的設置,而不是直接編輯這些檔案。
- nano 編輯器
較為簡單的文字編輯器,Ctrl+O 儲存檔案,Ctrl+X 退出檔案。
3.7.2 設置提示字元
提示字元由一組字元組成,每當 shell 準備接收命令時都會顯示這組字元。PS1 環境變數設置了提示字元所包含的內容,如果需要額外的輸入,可以使用 PS2、PS3 以及 PS4 的值。
| 特殊字元 | 描述 |
|---|---|
| \! | 顯示目前命令歷史記錄編號,包括為使用者名稱儲存的所有以前的命令 |
| \# | 顯示目前命令的命令編號,僅包括用於獲取 shell 的命令 |
| \$ | 根據使用者類型的不同,顯示使用者提示字元 $ 或 root 提示字元 # |
| \W | 僅顯示目前工作的基底名稱 (basename) |
| \[ | 出現在非列印字元序列之前。可用來向提示字元添加終端機控制序列,比如改變顏色、添加閃爍效果或使字元變粗 (所使用的終端機決定了最終可用的序列) |
| \] | 緊跟在非列印字元序列之後 |
| \\ | 顯示一個反斜線 |
| \d | 顯示目前日期的星期幾、月份以及日期 |
| \h | 顯示正在執行 shell 的電腦的主機名稱 |
| \n | 換行符號 |
| \nnn | 顯示替換 nnn 的八進位數所表示的字元 |
| \s | 顯示目前 shell 的名稱 |
| \t | 以小時、分鐘、秒的格式列印目前時間 |
| \u | 列印目前使用者名稱 |
| \w | 顯示目前工作目錄的完整路徑 |
如果僅臨時修改,例如 export PS1="[\t\w]\$"。
如果永久修改,需要向 ~/.bashrc 添加 PS1 值。
閱讀更多: Bash Prompt HOWTO
3.7.3 添加環境變數
有時可能需要向 .bashrc 檔案添加一些環境變數:
TMOUT — 設置在 Bash 自動退出之前 shell 可以處於非活動狀態多長時間。
PATH — 設置了對所使用命令進行搜尋的目錄。例如為了添加目錄 /home/yexca/bin,可添加以下程式碼:
PATH=$PATH:/home/yexca/bin ; export PATH
該範例首先將所有目前的路徑目錄 ($PATH) 讀取到新 PATH 變數中,然後添加 ~/bin 目錄,最後匯出新的 PATH 變數。
切勿將
.添加到 PATH 變數,可能存在安全風險。
WHATEVER — 可以建立自己的環境變數,為工作提供捷徑。為這些變數選擇一個未被使用的任何名稱,並賦予一個有用的值。例如:
MYWORKDIR=/home/yexca/work ; export MYWORKDIR
可透過輸入
cd $MYWORKDIR使設置的目錄成為目前目錄。
3.8 獲取關於命令的資訊
一些命令內建於 shell 中,例如 help | less 以瀏覽幫助資訊,或者 help command 以查看某命令的幫助資訊。
在命令中使用 --help 選項或 -h 選項以查看命令提供的幫助資訊。
還有 info 和 man command 命令學習某一特定命令。
說明頁 (man page) 是獲取命令以及 Linux 系統中其他基本組件相關資訊的最常用方法。
說明頁有 8 個章節:
| 節數 | 節名稱 | 描述 |
|---|---|---|
| 1 | 使用者命令 | 可以由一般使用者透過 shell 執行的命令 |
| 2 | 系統呼叫 | 某一應用程式中用來呼叫系統核心的程式設計函式 |
| 3 | C 函式庫函式 | 為特定程式設計函式庫提供介面的程式設計函式 |
| 4 | 裝置和特殊檔案 | 表示硬體裝置或軟體裝置的檔案系統節點 |
| 5 | 檔案格式和約定 | 檔案類型或特定的設定檔 |
| 6 | 遊戲 | 系統中可玩的遊戲 |
| 7 | 雜項 | 對相關主題 (如協定、檔案系統) 的概述 |
| 8 | 系統管理工具和守護行程 | 需要 root 或其他管理特權的命令 |
透過 man -k 可搜尋說明頁資料庫。若無搜尋結果可能是未初始化,使用 root 身份執行 mandb 以初始化資料庫。
透過例如 man 5 passwd 以顯示第 5 節內容。
瀏覽時透過 Page Down 和 Page Up 以翻頁,或使用 Enter 與方向鍵以移動一行。如果想要搜尋,使用正斜線 / 然後輸入要搜尋的內容,透過 n 重複向前搜尋,N 以重複向後搜尋。輸入 q 以退出。