在 Linux shell 環(huán)境中,sh、dash 和 bash 之間的關(guān)系既有繼承、兼容,也有替代和側(cè)重,核心在于歷史演變、標(biāo)準(zhǔn)遵循和性能優(yōu)化。
1.sh (Bourne Shell):歷史的起點(diǎn)
sh 指的是原始的 Bourne Shell,由 Stephen Bourne 在 1977 年左右為 Unix V7 開(kāi)發(fā)。
它是早期 Unix 系統(tǒng)的標(biāo)準(zhǔn)命令解釋器,奠定了現(xiàn)代 shell 的基礎(chǔ)語(yǔ)法和核心功能(如變量、控制流、管道、重定向等)。
其路徑通常是 /bin/sh。
關(guān)鍵點(diǎn): 現(xiàn)代 Linux 系統(tǒng)中 /bin/sh 通常不再是原始的 Bourne Shell 可執(zhí)行文件,而是一個(gè)指向其他兼容 shell(如 dash 或 bash)的符號(hào)鏈接。
2.bash (Bourne-Again Shell):增強(qiáng)的繼任者
bash 是 Bourne-Again Shell 的縮寫(xiě),由 Brian Fox 為 GNU 項(xiàng)目開(kāi)發(fā),首次發(fā)布于 1989 年。
設(shè)計(jì)目標(biāo): 完全兼容 sh (Bourne Shell) 的語(yǔ)法和特性,同時(shí)極大地?cái)U(kuò)展**了功能集。
*主要增強(qiáng)包括:
*命令行編輯(如 readline 庫(kù)支持的歷史記錄、補(bǔ)全)。
*作業(yè)控制(jobs, fg, bg)。
*數(shù)組變量。
*更強(qiáng)大的條件表達(dá)式 ([[ ... ]])。
*命令別名 (alias)。
*函數(shù)定義更靈活。
*大量?jī)?nèi)置命令和擴(kuò)展特性(如 select, $RANDOM, ${variable//pattern/replacement} 等)。
*路徑通常是 /bin/bash。
與 sh 的關(guān)系:
bash 兼容 Bourne Shell (sh) 語(yǔ)法。一個(gè)符合 POSIX sh 標(biāo)準(zhǔn)的腳本通常可以在 bash 下運(yùn)行。
在某些系統(tǒng)(尤其是較老的或某些 BSD 系統(tǒng))上,/bin/sh 可能直接指向 /bin/bash。
當(dāng) bash 以 sh 的名字被調(diào)用(例如通過(guò) /bin/sh 符號(hào)鏈接啟動(dòng),或者使用 bash --posix)時(shí),它會(huì)盡量模擬 POSIX sh 的行為,禁用一些非標(biāo)準(zhǔn)的 bash 擴(kuò)展特性,以提高兼容性。但這并非 100% 等同于原始的 Bourne Shell 或 dash。
3.dash (Debian Almquist Shell):輕量高效的 POSIX 實(shí)現(xiàn)
dash 是 Debian Almquist Shell 的縮寫(xiě),是 NetBSD 的 ash (Almquist Shell) 的一個(gè)現(xiàn)代分支,被 Debian 和 Ubuntu 等發(fā)行版采用。
ash 本身是一個(gè)輕量級(jí)、兼容 Bourne Shell 的 clone,由 Kenneth Almquist 在 1980 年代末開(kāi)發(fā)。
設(shè)計(jì)目標(biāo):
嚴(yán)格遵循 POSIX 標(biāo)準(zhǔn)。
極致的執(zhí)行速度和啟動(dòng)速度。
極小的內(nèi)存占用(Footprint)。
與 sh 的關(guān)系:
在 Debian、Ubuntu 及其衍生版 中,默認(rèn)的 /bin/sh 符號(hào)鏈接指向 /bin/dash,而不是 /bin/bash。
這意味著在這些系統(tǒng)上,當(dāng)你運(yùn)行一個(gè)以 #!/bin/sh 開(kāi)頭的腳本,或者直接在命令行輸入 sh 命令時(shí),實(shí)際執(zhí)行的是 dash。
與 bash 的關(guān)系:
dash 只保證實(shí)現(xiàn) POSIX sh 標(biāo)準(zhǔn)。它不包含 bash 的眾多擴(kuò)展特性(如數(shù)組、[[ ]]、source 命令(在 dash 中只能用 .)、高級(jí)參數(shù)擴(kuò)展等)。
腳本如果依賴(lài) bash 特有的語(yǔ)法或特性,在 /bin/sh 指向 dash 的系統(tǒng)上運(yùn)行會(huì)失?。▓?bào)語(yǔ)法錯(cuò)誤)。
dash 在啟動(dòng)速度和執(zhí)行簡(jiǎn)單腳本的效率上顯著優(yōu)于* bash,尤其是在系統(tǒng)初始化階段(init 腳本、systemd 服務(wù)單元中的 ExecStart= 命令等),這是 Debian/Ubuntu 選擇它作為默認(rèn) sh 的主要原因。

sh 是一個(gè)標(biāo)準(zhǔn)/接口: /bin/sh 是一個(gè)指向具體實(shí)現(xiàn)(dash 或 bash)的符號(hào)鏈接。這個(gè)實(shí)現(xiàn)必須符合 POSIX Shell 標(biāo)準(zhǔn)。
dash 是輕量級(jí)、嚴(yán)格 POSIX 的 sh 實(shí)現(xiàn): 專(zhuān)注于速度、效率和標(biāo)準(zhǔn)符合性,不提供額外擴(kuò)展。是 Debian/Ubuntu 系默認(rèn)的 sh。
bash 是功能豐富的超集: 完全兼容 sh 標(biāo)準(zhǔn),并提供了大量增強(qiáng)特性和更友好的交互體驗(yàn)。是許多發(fā)行版默認(rèn)的交互式登錄 shell* 和 RHEL/Fedora 等發(fā)行版默認(rèn)的 /bin/sh 實(shí)現(xiàn)(或指向)。但其啟動(dòng)和運(yùn)行比 dash 稍慢。
兼容性是關(guān)鍵問(wèn)題:
如果一個(gè)腳本聲明 #!/bin/sh,它應(yīng)該只使用 POSIX sh 標(biāo)準(zhǔn)語(yǔ)法,這樣才能在指向 dash 或 bash 的系統(tǒng)上都正常運(yùn)行。
如果一個(gè)腳本需要用到 bash 的擴(kuò)展功能,它必須*聲明 #!/bin/bash(或完整路徑)。否則在 /bin/sh 指向 dash 的系統(tǒng)上會(huì)出錯(cuò)。
*反之,用 #!/bin/bash 的腳本在只安裝了 dash 的系統(tǒng)上(雖然罕見(jiàn))也無(wú)法運(yùn)行。
何時(shí)使用哪個(gè)?
寫(xiě)系統(tǒng)級(jí)腳本/追求最大兼容性/需要極速啟動(dòng): 用 #!/bin/sh,并嚴(yán)格遵守 POSIX shell 語(yǔ)法*(無(wú)論系統(tǒng)實(shí)際鏈接到 dash 還是 bash)。這是最佳實(shí)踐。
*需要 bash 的強(qiáng)大功能或交互式使用: 用 #!/bin/bash(腳本)或直接在 bash 終端中工作。
*系統(tǒng)初始化腳本/短小腳本: 系統(tǒng)默認(rèn)使用 /bin/sh(即 dash)是為了速度。
*用戶(hù)日常命令行: 通常默認(rèn)使用 bash(或其他如 zsh),因?yàn)樗换ンw驗(yàn)好。
理解 sh、dash、bash 之間的關(guān)系,特別是 /bin/sh 符號(hào)鏈接的指向差異,對(duì)于編寫(xiě)可移植的 shell 腳本和調(diào)試腳本兼容性問(wèn)題至關(guān)重要。