Bash，Unix shell 的一種，在 1987 年由布萊恩福克斯為了 GNU 計劃而編寫。1989 年釋出第一個正式版本，原先是計劃用在 GNU 作業系統上，但能運行於大多數類 Unix 系統的作業系統之上，包括 Linux 與 Mac OS X v104 起至 macOS Mojave 都將它作為預設 shell，而自 macOS Catalina，預設 Shell 以 zsh 取代。 Bash 是 Bourne shell 的後繼相容版本與開放原始碼版本，它的名稱來自 Bourne shell（sh）的一個雙關語（Bourne again born again）：BourneAgain SHell。 Bash 是一個命令處理器，通常運行於文字視窗中，並能執行使用者直接輸入的命令。Bash 還能從檔案中讀取命令，這樣的檔案稱為指令碼。和其他 Unix shell 一樣，它支援檔名替換（萬用字元匹配）、管道、here 文件、命令替換、變數，以及條件判斷和迴圈遍歷的結構控制語句。包括關鍵字、語法在內的基本特性全部是從 sh 借鑑過來的。其他特性，例如歷史命令，是從 csh 和 ksh 借鑑而來。總的來說，Bash 雖然是一個滿足 POSIX 規範的 shell，但有很多擴充套件。 一個名為 Shellshock 的安全漏洞在 2014 年 9 月初被發現，並迅速導致網際網路上的一系列攻擊。這個漏洞可追溯到 1989 年釋出的 103 版本。 歷史 由於理查德斯托曼對於之前一位開發者的進度不滿，布萊恩福克斯從 1988 年 1 月 10 日開始開發 Bash。斯托曼和自由軟體基金會希望到一個能夠執行已有的 shell 指令碼的自由軟體。他們把這看作是建成一個基於 BSD 和 GNU 的完全自由的作業系統的戰略的重要部分。這是他們自己注資的幾個專案之一。福克斯作為自由軟體基金會的僱員承擔這項工作。1989 年 6 月 8 日，福克斯釋出 Bash 的 beta 版本，版本號為99。在福克斯離開於 1992 年中期到 1994 年中期的某個時候離開自由軟體基金會之前，他一直擔任 Bash 的主要維護者。之後，他的工作被傳遞給另一個早期貢獻者，切特雷米（Chet Ramey）。 從那時起，在 Linux 使用者當中 sh 在很大度上成為最流行的 shell，併成為許多 Linux 發行版預設的互動式 shell（不過 Almquist shell 可能是預設的指令碼 shell）。在蘋果公司的 OS X 作業系統上也是如此。Bash 也被移植到 Microsoft Windows（透過 Cygwin 和 MinGW）。透過 DJGPP 專案，Bash 被移植到了 DOS。透過許多終端模擬軟體，Bash 被移植到 Novell NetWare 和 Android。微軟在 2016 年的 Build 大會上宣佈，Windows 10 新增一個 Linux 子系統，完全支援 Bash 和其他 Ubuntu 下的二進位制程式。 2014 年 9 月 24 日，Stephane Chazelas，一位工作於英國，致力於 UnixLinux 和網路通訊方面的專家，發現 Bash 的一個安全漏洞。這個漏洞被命名為 Shellshock，並被分配編號 CVE20146271、CVE20146277、CVE20147169。這個漏洞非常嚴重，因為使用 Bash 的 CGI 指令碼會變得脆弱，使得攻擊者可以執行任意的程式碼。這個漏洞與 Bash 透過環境變數把函式定義傳遞給 shell 子程序的方式有關。 語法與特性 bash 的命令語法是 Bourne shell 命令語法的超集。數量龐大的 Bourne shell 指令碼大多不經修改即可以在 bash 中執行，只有那些引用了 Bourne 特殊變數或使用了 Bourne 的內建命令的指令碼才需要修改。bash 的命令語法很多來自 Korn shell（ksh）和 C Shell（csh），例如命令列編輯，命令歷史，目錄棧，RANDOM 和 PPID 變數，以及 POSIX 的命令置換語法：。作為一個互動式的 shell，按下 TAB 鍵即可自動補全已部分輸入的程式名，檔名，變數名等等。 使用 function 關鍵字時，Bash 的函式宣告與 BourneKornPOSIX 指令碼不相容（Korn shell 有同樣的問題）。不過 Bash 也接受 BourneKornPOSIX 的函式宣告語法。因為許多不同，Bash 指令碼很少能在 Bourne 或 Korn 直譯器中執行，除非編寫指令碼時刻意保持相容性。然而，隨著 Linux 的普及，這種方式正變得越來越少。不過在 POSIX 模式下，Bash 更加符合 POSIX。 bash 的語法針對 Bourne shell 的不足做了很多擴充套件。其中的一些列舉在這裡。 花括號擴充套件 花括號擴充套件是一個從 C shell 借鑑而來的特性，它產生一系列指定的字串（按照原先從左到右的順序）。這些字串不需要是已經存在的檔案。 echo a pcdb e ape ace ade abe echo abcdef ad ae af bd be bf cd ce cf 花括號擴充套件不應該被用在可移植的 shell 指令碼中，因為 Bourne shell 產生的結果不同。 binsh 傳統的 shell 並不產生相同結果 echo a pcdb e a pcdb e 當花括號擴充套件和萬用字元一起使用時，花括號擴充套件首先被解析，然後正常解析萬用字元。因此，可以用這種方法獲得當前目錄的一系列 JPEG 和 PNG 檔案。 ls jpgjpegpng 首先擴充套件為 jpg jpeg png，然後解析萬用字元 echo pngjp e g echo 顯示擴充套件結果；花括號擴充套件可以巢狀。 除了列舉備選項，還可以用 在花括號擴充套件中指定字元或數字範圍。較新的 Bash 版本接受一個整數作為第三個引數，指定增量。 echo 110 1 2 3 4 5 6 7 8 9 10 echo file 14txt file1txt file2txt file3txt file4txt echo ae a b c d e echo 1103 1 4 7 10 echo aj3 a d g j 當花括號擴充套件和變數擴充套件一起使用時，變數擴充套件解析於花括號擴充套件之後。有時有必要使用內建的 eval 函式 start1 end10 echo startend 由於解析順序，無法得到想要的結果 110 eval echo startend 首先進行變數擴充套件的解析 1 2 3 4 5 6 7 8 9 10 使用整數 與 Bourne shell 不同的是 bash 不用另外生成程序即能進行整數運算。bash 使用 命令和 變數語法來達到這個目的： VAR55 將整數 55 賦值給變數 VAR VAR VAR 1 變數 VAR 加 1。注意這裡沒有 VAR 另一種方法給 VAR 加 1。使用 C 語言風格的字首自增 VAR 另一種方法給 VAR 加 1。使用 C 語言風格的字尾自增 echo VAR 22 VAR 乘以 22 並將結果送入命令 echo VAR 22 同上，但為過時用法 命令可以用於條件語句，因為它的退出狀態是 0 或者非 0（大多數情況下是 1），可以用於是與非的條件判斷： if VAR Y 3 X 2 then echo Yes fi Z 23 echo Yes 命令支援下列比較運算子： ，和 。 bash 不能在自身程序內進行浮點數運算。當前有這個能力的 unix shell 只有 KornShell 和 Z shell。 輸入輸出重定向 bash 擁有傳統 Bourne shell 缺乏的 IO 重定向語法。bash 可以同時重定向標準輸出和標準錯誤，這需要使用下面的語法： command file 這比等價的 Bourne shell 語法 command file 21 來的簡單。205b 版本以後，bash 可以用下列語法重定向標準輸入至字串（稱為 here string）： command string to be read as standard input 如果字串包括空格就需要用引號包裹字串。 例子 重定向標準輸出至檔案，寫資料，關閉檔案，重置標準輸出。 生成標準輸出（檔案描述符 1）的複製檔案描述符 6 exec 61 開啟檔案 testdata 以供寫入 exec 1testdata 產生一些內容 echo datadatadata 關閉檔案 testdata exec 1 使標準輸出指向 FD 6（重置標準輸出） exec 16 關閉 FD6 exec 6 開啟及關閉檔案 開啟檔案 testdata 以供讀取 exec 6testdata 讀檔案直到檔案尾 while read u 6 dta do echo dta done 關閉檔案 testdata exec 6 抓取外部命令的輸出 執行 find 並且將結果存於 VAR 搜尋以 h 結尾的檔名 VARfind name h 程序內的正則表示式 bash 30 支援程序內的正則表示式，使用下面的語法： string regex 正則表示式語法同 regex 7 man page 所描述的一致。正則表示式匹配字串時上述命令的退出狀態為 0，不匹配為 1。正則表示式中用圓括號括起的子表示式可以訪問 shell 變數 BASH_REMATCH，如下： if abcfoobarbletch foo bar bl then echo The regex matches echo BASH_REMATCH outputs foobarbletch echo BASH_REMATCH 1 outputs bar echo BASH_REMATCH 2 outputs etch fi 使用這個語法的效能要比生成一個新的程序來執行 grep 命令優越，因為正則表示式匹配在 bash 程序內完成。如果正則表示式或者字串包括空格或者 shell 關鍵字，（諸如 或者 ），就需要用引號包裹。Bash 4 開始的版本已經不需要這麼做了。 跳脫字元 string 形式的字串會被特殊處理。字串會被展開成 string，並像 C 語言那樣將反斜槓及緊跟的字元進行替換。反斜槓轉義序列的轉換方式如下： 跳脫字元 跳脫字元 擴充套件成 a 響鈴符 b 退格符 e ANSI 轉義符，等價於 033 f 饋頁符 n 換行符 r 回車符 t 水平製表符 v 垂直製表符 反斜槓 單引號 nnn 十進位制值為 nnn 的 8bit 字元（1－3 位） xHH 十六進位制值為 HH 的 8bit 字元（1 或 2 位） cx controlX 字元 擴充套件後的結果將被單引號包裹，就好像美元符號一直就不存在一樣。 雙引號包裹的字串前若有一個美元符號將會使得字串被翻譯成符合當前 locale 的語言。如果當前 locale 是 C 或者 POSIX，美元符號會被忽略。如果字串被翻譯並替換，替換後的字串仍被雙引號包裹。 關聯陣列 Bash 40 開始支援關聯陣列，透過類似 AWK 的方式，對於多維陣列提供了偽支援。 declare A a 宣告一個名為 a 的偽二位陣列 i1 j2 a ij5 將鍵 ij 與值 5 對應 echo a ij 移植性 呼叫 Bash 時指定 posix 或者在指令碼中宣告 set o posix ，可以使得 Bash 幾乎遵循 POSIX 10032 標準。若要保證一個 Bash 指令碼的移植性，至少需要考慮到 Bourne shell，即 Bash 取代的 shell。Bash 有一些傳統的 Bourne shell 所沒有的特性，包括以下這些： 某些擴充套件的呼叫選項 命令替換（即 ）（儘管這是 POSIX 10032 標準的一部分） 花括號擴充套件 某些陣列操作、關聯陣列 擴充套件的雙層方括號判斷語句 某些字串生成操作 程序替換 正則表示式匹配符 Bash 特有的內建工具 協程序 鍵盤快捷鍵 Bash 預設使用 Emacs 的快捷鍵，可以透過 set o vi 讓它使用 Vi 的快捷鍵 程序管理 Bash 有兩種執行命令的模式：批處理模式、併發模式。 批處理模式 要以 批處理模式 執行命令（即按照順序），必須用；分隔，例子如下： command1 command2 在這個例子中，當 command1 執行完畢，即執行 command2。 併發模式 使 command1 後臺執行，則單獨在結尾處使用 ，例子如下： command1 要併發執行兩個命令，它們必須用 分隔，例子如下： command1 command2 在這種情況下，command1 在後臺執行（透過 ），從而立即將控制返回到 shell，以執行 command2。 透過 可以將當前程序掛起（放置後臺並暫停執行），可透過 fg 命令恢復至前臺，也透過 bg 將掛起的程序後臺執行。 檢視程序狀態 所有程序的情況，我們可以透過 jobs 命令檢視，包含正在後臺執行和停止了的。 jobs 1 Running command1 2 Stopped command2 上例的輸出結果中，中括號包圍的數字（如： 1 和 2 ）為 job 的 ID 號。加號 用於指定 fg 和 bg 命令的預設物件 job。減號 用於指定，若當前的預設物件 job 退出後，下一個預設物件 job 是誰。Running 和 Stopped 表示程序狀態。 最後一個欄位為命令。 總結： 一般命令在前臺執行（fg），執行完畢後，控制返回給使用者。 在命令後面加上 ，它會在後臺執行（bg），並將特殊的環境變數 設定為該任務的程序 ID。這時 shell 可以併發執行其他命令。 後臺程式試圖寫入資料到終端裝置時（與寫入標準輸出不同）可能被阻塞。 shell 可以等待一個後臺任務執行完成，只需使用 wait 命令，加上程序 ID 或者任務序號；也可以等待所有的後臺任務，只需使用不加引數的 wait 啟動指令碼 bash 啟動的時候會執行各種不同的指令碼。 當 bash 作為一個登入的互動 shell 被呼叫，或者作為非互動 shell 但帶有 login 引數被呼叫時，它首先讀入並執行檔案 etcprofile。然後它會依次尋找～bash_profile，bash_login，和～profile，讀入並執行第一個存在且可讀的檔案。noprofile 引數可以阻止 bash 啟動時的這種行為。 當一個登入 shell 退出時，bash 讀取並執行～bash_logout 檔案，如果此檔案存在。 當一個互動的非登入 shell 啟動後，bash 讀取並執行～bashrc 檔案。這個行為可以用 norc 引數阻止。rcfile file 引數強制 bash 讀取並執行指定的 file 而不是預設的～bashrc。 如果用 sh 來呼叫 bash，bash 在啟動後進入 posix 模式，它會盡可能模仿 sh 歷史版本的啟動行為，以便遵守 POSIX 標準。用 sh 名字呼叫的非互動 shell 不會去讀取其他啟動指令碼，rcfile 引數無效。 當 bash 以 POSIX 模式啟動時（例如帶有 posix 引數）它使用 POSIX 標準來讀取啟動檔案。在此模式下，互動 shells 擴充套件變數 ENV，從以此為檔名的檔案中讀取命令並執行。 bash 會探測自己是不是被遠端 shell 守護程式執行（通常是 rshd）。如果是，它會讀取並執行～bashrc 中的命令。但是 rshd 一般不會用 rc 相關引數呼叫 shell，也不會允許指定這些引數。 Bash 與 Bourne shell 和 csh 啟動指令碼的比較 Bash 的特性是從 Bourne shell 和 csh 發展而來，因此一定程度上允許同 Bourne shell 的啟動檔案共享，並提供一些 csh 使用者熟悉的啟動特性。 設定可繼承的環境變數 Bourne shell 登陸時使用～profile 來設定環境變數，這些環境變數可以被子程序繼承。Bash 可以以相容的方式使用～profile ，只需在 Bash 自有的指令碼中顯式執行下面這行程式碼。透過在～profile 中避免使用 Bash 特有的語法，就可以和 Bourne shell 保持相容性。 profile 別名和函式 更通用的函式以及借鑑自 csh 的 別名 alias 很大程度上取代了 Bourne shell 的別名 alias 和函式。然而這兩個特性一般不能從登入式 shell 中繼承，在該登入式 shell 的子 shell 中，它們必須被重新定義。儘管有個環境變數 ENV 可以被用於這個問題，不過 csh 和 Bash 都可以用子 shell 的啟動指令碼直接處理。在 Bash 當中，bashrc 是互動式子 shell 啟動時執行的指令碼。如果想要在登入式 shell 中使用～bashrc 定義的函式，可以在～bash_login 的環境變數後面加上這樣一行： bashrc 登入與登出時執行的命令 最初登入時，csh 執行～login ，可以執行一些只在登入時執行的操作，例如顯示系統負載、硬碟狀態、是否收到新郵件、在日誌中記錄登入時間，等等。Bourne shell 可以在～profile 檔案中模擬這種行為，但並沒有預先定義檔名。可以在～bash_profile 檔案的環境變數設定和函式定義的後面新增這樣一行： bash_login 與之類似，csh 還有一個檔案～logout ，這個檔案只在登入式 shell 退出時執行。Bash 與之對應的檔案是～bash_logout ，並且不需要專門的設定。在 Bourne shell 中，trap 這個內建工具可以實現類似的效果。 相容舊環境的 Bash 啟動指令碼示例 下面這個～bash_profile 的框架與 Bourne shell 相容，並且為～bashrc 和～bash_login 提供類似於 csh 的語義。r 檔名 測試指定檔案是否存在，如果不存在，跳過 後面的部分 r profile profile 只使用 Bourne shell 的語法設定環境變數 if n PS1 then 判斷是否是互動式 shell r bashrc bashrc 載入～bashrc（tty、prompt、函式設定等） r bash_login bash_login 執行登入式 shell 登入時的任務 fi if 塊的結束標誌 Bash 啟動指令碼與作業系統相關的問題 一些 Unix 和 Linux 版本常在 etc 放置 Bash 的系統級啟動指令碼。Bash 在其標準的初始化過程中執行它們，不過其他啟動指令碼可以按照不同於 Bash 啟動序列文件所述的順序來讀取這些檔案。root 使用者的檔案預設內容，以及新使用者被建立時系統提供的預設檔案可能有問題。啟動 X Window 系統 的啟動指令碼可能使用使用者的 Bash 啟動指令碼嘗試在 視窗管理器 啟動之前設定使用者的環境變數。這些問題常常可以透過使用～xsession 或者～xprofile 來讀取～profile 而解決。 參見 Unix shell 腳註 外部連結 GNU Bash 主頁 GNU Bash 在 GNU 的主頁 bashdb，帶有偵錯程式的 Bash Bash 入門指南 Bash 同標準 unix shell 的不同 Bash by example Bash 基礎程式設計 CategoryUnix shells Category 指令碼語言 CategoryGNU 計劃軟體 Category 面向文字程式語言