深入了解定製 Bash
操作系統的最外層 —— 也就是跟你直接打交道的 —— 叫做 shell(「外殼」)。Fedora 預裝了好幾種不同的 shell。shell 可以是圖形界面,或者字元界面。在文檔中,你常常能見到兩個母縮寫詞 GUI ( 圖形用戶界面 )跟 CLI( 命令行界面 ),它們用來區分圖形和基於字元的 shell/界面。GNOME 和 Bash 分別是 Fedora 默認的圖形和命令行界面,不過你也可以使用其它 GUI 或者 CLI shell。
接下來在這篇文章中,我們會討論一些比較推薦的 Bash 字元界面的點文件配置。
Bash 概覽
Bash 參考手冊中寫道:
根本上來說,shell 只是一個能執行命令的宏處理器。宏處理器這個詞意味著通過擴展文本跟符號,從而構成更複雜的表達式。
Bash 參考手冊 第五版,Bash 5.0 2019 年 5 月
除了能使用其它程序之外,Bash shell 還含有一些內置命令和關鍵字。Bash 內置功能很強大,甚至能夠作為一門 高級語言 獨當一面。Bash 的幾個關鍵字和操作符類似於 C 語言。
Bash 能夠以互動式或非互動式模式啟動。Bash 的交互模式是一個很多人都熟悉的典型的終端/命令行界面。GNOME 終端 默認以交互模式打開 Bash。Bash 在非交互模式下運行的例子是,當命令和數據從文件或 shell 腳本通過 管道 傳送到 Bash 時。其它 Bash 可以運行的模式包括: 登錄 、 非登錄 、 遠程 、POSIX、Unix sh、 受限 ,以及使用與用戶不同的 UID/GID 模式。各種模式是可以相互組合的。比如,互動式 + 受限 + POSIX 或者非互動式 + 非登錄 + 遠程。不同的啟動模式,決定著 Bash 所讀取的啟動文件。理解這些操作模式,有助於幫助我們修改啟動文件。
根據 Bash 參考手冊,它會:
- 從文件中...、從作為
-c
調用選項傳入參數的字元...,或者從用戶的終端中讀取輸入。- 將輸入分解成單詞和操作符,遵循 [它的] 引用規則。...這些標記使用元字元隔開。這一步執行別名展開。
- 將標記解析成簡單與複合命令。
- 執行各種 shell 展開...,將展開之後的標記分解成文件名...以及命令和參數的列表。
- 執行必要的重定向...並從參數列表中去除重定向操作符及其操作數。
- 執行命令。
- 必要時等待命令完成,並收集退出狀態。
Bash 參考文檔 第五版,Bash 版本 5.0 2019 年 5 月
當用戶開啟終端模擬器進入命令行環境時,便啟動了一次互動式 shell 會話。GNOME 終端默認以非登錄模式為用戶打開 Shell。你可以在 「 編輯 → 首選項 → 配置文件 → 命令 」 中配置 GNOME 終端以何種模式(登錄與非登錄式)啟動。也可以在 Bash 啟動時通過向其傳遞 -login
標誌來要求進入登錄模式。要注意一點,Bash 的登錄模式與非交互模式並不互斥。可以讓 Bash 同時以登錄模式和非交互模式運行。
啟動 Bash
除非傳入 -noprofile
選項,否則登錄模式的 Bash shell 會默認讀取並執行某些初始化文件中命令。如果 /etc/profile
存在,它會是第一個被執行的文件,緊接著是按 ~/.bash_profile
、~/.bash_login
或 ~/.profile
順序找到的第一個文件。當用戶退出登錄模式的 shell 時,或者有腳本在非互動式登錄模式的 shell 中調用了內置 exit
命令,Bash 會讀取並執行 ~/.bash_logout
中的命令,如果 /etc/bash_logout
存在的話,會緊接著執行它。通常來說,/etc/profile
會 援引 /etc/bashrc
文件,讀取並執行其中的命令,然後查找並讀取執行 /etc/profile.d
目錄中以 .sh
結尾的文件。同樣的,~/.bash_profile
通常也會 援引 ~/.bashrc
文件。/etc/bashrc
和 ~/.bashrc
都會進行檢查,避免重複 援引 。
(LCTT 譯註:在 Bash 中,腳本會通過 source
或 .
命令來將另外一個腳本引入其中,這個行為稱之為 「source」、「sourcing」,但是該行為一直沒有公認且常用的翻譯方法。經過多番斟酌,我認為可以譯做「援引」,理由如下:1、「援引」具有「引用、引入」的意思,符合該行為;2、「援」這個詞的發音和「source」 常見的漢語意思「源」同音,便於記憶。以上是我們的愚見,供大家參考討論。—— 老王,2020/7/19)
一個互動式的 shell,如果不是登錄 shell,那麼當它第一次被調用的時候,會執行 ~/.bashrc
文件。這是用戶在 Fedora 上打開終端時通常會進入的 shell 類型。當 Bash 以非交互模式啟動 —— 就像運行腳本時那樣 —— 它會尋找 BASH_ENV
環境變數。如果找到了,就會展開它的值作為文件名,接著讀取並執行該文件。效果跟執行以下命令相同:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
值得注意的是,不會使用 PATH
環境變數的值來搜索該文件名(LCTT 譯註:意即不會檢索搜索路徑)。
重要的用戶點文件
Bash 最廣為人知的用戶點文件是 ~/.bashrc
。通過編輯該文件,可以設置大多數個性化選項。由於我們常常需要設置一些選項,會改動上面提及甚至沒有提及的文件,所以大部分自定義選項會成為一個麻煩事。Bash 環境具有很高的可定製性,正是為了適應不同用戶的不同需求。
當登錄 shell 正常退出時,如果 ~/.bash_logout
和 /etc/bash_logout
存在,它們會被調用。下一幅圖展示了 Bash 作為互動式 shell 啟動時的過程。例如,當用戶從桌面環境打開終端模擬器時,會按照以下順序進行。
我們已經知道,在不同的啟動模式下,Bash 會執行不同的命令,所以很明顯,只有幾種最需要關注的典型啟動模式。分別是非交互、互動式登錄 shell,和非互動式、互動式非登錄 shell。如果想定義某些全局環境,那麼需要將一個具有唯一名稱、以 .sh
為後綴的文件(例如 custom.sh
)放置在 /etc/profile.d
目錄。
對於非互動式非登錄啟動方式,需要特別注意。在這種模式下,Bash 會檢查 BASH_ENV
變數。如果定義了該變數,Bash 會援引它所指向的文件。另外,處理 BASH_ENV
時並不會使用 PATH
變數所存儲的值(LCTT 譯註:意即不會檢索搜索路徑),所以它必須包含執行文件的絕對路徑。比如說,如果有人希望非互動式執行腳本時,shell 能讀取 ~/.bashrc
文件中的設置,那麼他可以把類似下面這樣的內容放在一個名為 /etc/profile.d/custom.sh
的文件中...
# custom.sh
.
.
.
# 如果使用 Fedora Workstation
BASH_ENV="/home/username/.bashrc"
.
.
.
# 如果使用 Fedora Silverblue Workstation
BASH_ENV="/var/home/username/.bashrc"
export BASH_ENV
上面這份腳本會讓每個 shell 腳本在運行之前先執行該用戶的 ~/.bashrc
。
用戶一般都會自定義他們的系統環境,以便契合他們自己的工作習慣與偏好。舉例來說,用戶可以通過別名來實現這種程度的自定義。擁有相同起始參數、需要頻繁使用的命令是製作別名的最佳選擇。以下展示了一些來自 ~/.bashrc
文件中定義的別名。
# .bashrc
# 執行全局文件
if [ -f /etc/bashrc ];
then . /etc/bashrc
fi
.
.
.
# 用戶別名和函數
alias ls='ls -hF --color=auto'
alias la='ls -ahF --color=auto'
# 讓 dir 命令用起來像在 Windows 那樣
alias dir='ls --color=auto --format=long'
# 用顏色高亮 grep 結果
alias grep='grep --color=auto'
在系統中,別名是一種自定義各種命令的方法。它能減少擊鍵次數,而且讓命令用起來更方便。針對用戶級別的別名通常存放在該用戶的 ~/.bashrc
文件中。
如果你發現自己經常要去歷史中查找曾經執行過的某條命令,那可能需要改改歷史設置了。你依然可以在 ~/.bashrc
文件中設置針對用戶級別的歷史選項。比如說,如習慣同時使用多個終端,那你可能要啟用 histappend
選項。某些 Bash 相關的 shell 選項本質上是布爾值(接收 on
或 off
),通常可以用內置命令 shopt
啟用或禁用。接收更複雜的值的 Bash 選項(如 HISTTIMEFORMAT
),常常通過賦值給環境變數來達到配置目的。以下演示如何以 shell 選項和環境變數定製 Bash。
# 配置 Bash 歷史
# 用製表符擴展目錄環境變數,並設置 histappend
shopt -s direxpand histappend
# ignoreboth 等同於 ignorespace 和 ignoredup
HISTCONTROL='ignoreboth'
# 控制 `history` 輸出中的時間格式
HISTTIMEFORMAT="[%F %T] "
# 無限歷史記錄
# NB:在新版 Bash 中,任何 < 0 的寫法都有效,但是在 CentOS/RHEL 中,只有這樣才行得通
HISTSIZE=
HISTFILESIZE=
# 或者對於使用新版 Bash 的人
HISTSIZE=-1
HISTFILESIZE=-1
上面例子中的 direxpand
選項,可以讓 Bash 在文件名補全時,用單詞展開結果替換目錄名。它會改變 readline 編輯緩衝區的內容,所以你所輸入的東西已經被補全得到的結果替換了。
HISTCONTROL
變數用於啟用或禁用命令歷史的某些過濾選項。重複行、以空白打頭的行,都能通過該選項將它們從命令歷史中過濾掉。引用自 Dusty Mabe,這是我從他那兒得到的技巧:
ignoredup
可以讓歷史不記錄重複條目(如果你反覆執行同一條命令)。ignorespace
會忽略前面有空白的條目,當你在設置一個包含敏感信息的環境變數或者執行一條不想被記錄進磁碟的命令時,這就很有用。ignoreboth
相當於這兩條選項的結合體。Dusty Mabe – Redhat首席軟體工程師,2020.6.19
對於命令行重度用戶,Bash 有一個 CDPATH
環境變數。如果 CDPATH
包含一系列供 cd
命令搜索的目錄,且提供一個相對路徑作為第一個參數,那麼它會按順序檢查所有列出的目錄,尋找匹配的子目錄並切換到第一個匹配結果目錄。
# .bash_profile
# 設置 CDPATH
CDPATH="/var/home/username/favdir1:/var/home/username/favdir2:/var/home/username/favdir3"
# 也可以寫成這樣
CDPATH="/:~:/var:~/favdir1:~/favdir2:~/favdir3"
export CDPATH
CDPATH
通常像 PATH
一樣的方式進行更新 —— 通過在賦值右側引用自身來保留原來的值。
# .bash_profile
# 設置 CDPATH
CDPATH="/var/home/username/favdir1:/var/home/username/favdir2:/var/home/username/favdir3"
# 或者寫成這樣
CDPATH="/:~:/var:~/favdir1:~/favdir2:~/favdir3"
CDPATH="$CDPATH:~/favdir4:~/favdir5"
export CDPATH
PATH
是另一個極其重要的變數。它是系統上的命令的搜索路徑。注意,有些應用要求將它們自己的目錄加入 PATH
變數,這樣才能正常使用。跟 CDPATH
一樣,通過在賦值右側引用原值來追加新值到 PATH
變數。如果你希望將新值前置,只需要把原來的值($PATH
)放到列表末尾即可。還有注意的是在 Fedora,這一列值通過冒號分隔(:
)。
# .bash_profile
# 添加 PATH 值到 PAHT 環境變數
PATH="$PATH:~/bin:~:/usr/bin:/bin:~/jdk-13.0.2:~/apache-maven-3.6.3"
export PATH
命令提示符是另一個流行的自定義選項。它有七個可定製的參數:
PROMPT_COMMAND
:如果設置了,會在每一個主提示符($PS1
)出現之前執行該值。PROMPT_DIRTRIM
:如果設置成大於零的數,則該值用作展開w
和W
提示符字元串轉義符時保留的尾隨目錄組件數量。刪除的字元將替換為省略號。PS0
:這個參數的值像PS1
一樣展開,在互動式 shell 讀取命令之後、執行命令之前展示。PS1
:主提示符字元串。默認值是s-v$
。PS2
:次提示符字元串。默認是>
。在顯示之前,PS2
像PS1
那樣展開。PS3
:這個參數的值用作select
命令的提示符。如果這個變數沒有設置,select
命令會用#?
作為提示符。PS4
:這個參數的值像PS1
那樣展開,如果設置了-x
選項,這個展開值會在命令行被回顯之前作為提示符顯示。展開後的值的第一個字元在必要時會複製數次,指示間接層數。默認值是+
。Bash 參考文檔 第五版,Bash 版本 5.0 2019 年 5 月
Bash 的這一個方面就可以用整篇文章來討論。你可以找到許許多多信息和例子。在本文末尾鏈接的存儲庫中提供了一些點文件範例,包括提示符重新配置。你可以隨意使用該存儲庫中的例子進行學習和體驗。
總結
既然你已經掌握了一些 Bash 的工作原理,那就可以輕鬆修改你的 Bash 點文件,滿足你自己的需求和習慣。美化你的提示符,製作一些別名,這樣你的電腦才真的屬於你。查看 /etc/profile
、/etc/bashrc
和 /etc/profile.d/
這些文件的內容,獲得一些啟發。
你也可以在這裡寫一些關於終端模擬器的評論。有很多辦法可以將你最喜歡的終端,完全配置成你想要的樣子。你或許早就想到了,但是通常可以通過……嗯……用戶家目錄的點文件實現這個目的。終端模擬器也可以作為登錄會話啟動,有些人總喜歡用登錄環境。你使用終端和電腦的姿勢,取決於你如何修改(或不修改)你的點文件。
如果你很好奇自己的命令行處於什麼會話狀態,使用下面這個腳本來判斷一下。
#!/bin/bash
case "$-" in
(*i*) echo This shell is interactive ;;
(*) echo This shell is not interactive ;;
esac
把這幾行放到一個文件里,加上可執行許可權,然後運行,就能看到你當前處於何種類型的 shell。$-
在 Bash 中是一個變數,如果是互動式 shell,它會包含字母 i
。此外,你可以直接輸出 $-
變數然後檢查它的輸出中是否含有 i
標記。
$ echo $-
參考信息
可以參考以下資料以獲取更多信息和示例。Bash 手冊也是一個很好的信息來源。請注意,確保你的本地手冊頁記錄了你當前運行的 Bash 版本的特性,因為在網上找到的信息有時可能太老(過時了)或太新(你的系統還沒有安裝)。
- https://opensource.com/tags/command-line
- https://opensource.com/downloads/bash-cheat-sheet(在該網站中,你必須要輸入一個有效的電子郵箱地址,或者註冊,才能下載。)
- https://opensource.com/article/19/12/bash-script-template
對本文有各種形式(點文件示例、提示,以及腳本文件)貢獻的社區成員:
- Micah Abbott – 首席質量工程師
- John Lebon – 首席軟體工程師
- Dusty Mabe – 首席軟體工程師
- Colin Walters – 高級首席軟體工程師
示例點文件和腳本可以在這個存儲庫中找到:
請仔細檢查上面所提供的存儲庫中的信息。有些可能已經過時了。裡面還包含很多開發中的自定義腳本和 寵物容器 配置例子,那些不是點文件。我推薦從 John Lebon 的點文件開始學習,從頭到尾都含有完善的解說,它們是我見過的最詳細的,並且包含了非常好的描述。祝你學得開心!
via: https://fedoramagazine.org/customizing-bash/
作者:Stephen Snow 選題:lujun9972 譯者:nophDog 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive