Linux 腳本首行的秘密:究竟 #!/usr/bin/env bash 與 #!/bin/bash 代表什麼?
在 Linux 中編寫腳本時,我們習慣性地會在最上方寫上這行程式碼。
#!/usr/bin/env bash
或者
#!/bin/bash
表面上看起來像註解,但這一行的真實身份究竟是什麼?它們之間又存在什麼差異呢?本文將深入解析這行程式碼的奧秘,並探討在不同情境下應選擇哪種寫法。
1. 這不是註解:什麼是 shebang?{#sec-9f8041c620ba}
以 #! 開頭的這一行,我們稱之為 shebang。
#!/bin/bash
對於 Shell 來說,因為它以 # 開頭,所以看起來確實像是「註解」。
然而,對於作業系統(核心)而言,這並非註解,而是:
「指示作業系統,告知執行此腳本的直譯器程式位於何處的指令。」
換句話說,
#!/bin/bash→ 「請使用/bin/bash來執行此檔案。」#!/usr/bin/env bash→ 「請透過env尋找bash直譯器,並使用它來執行此檔案。」
這就是它們各自的含義。
2. 核心如何執行腳本?{#sec-33d96b8d8f01}
將執行過程極度簡化,大致如下:
- 使用者執行具有執行權限的腳本
chmod +x script.sh
./script.sh
- 核心讀取
script.sh - 檢查檔案的前兩個字元是否為
#! - 若是,則將該行剩餘部分
- 識別為「直譯器的路徑 + 參數」,並
- 執行該程式,同時將腳本檔案路徑作為參數傳遞
例如,如果 script.sh 的首行是這樣:
#!/bin/bash
核心實際執行的動作,大致可以這樣理解:
/bin/bash script.sh
換句話說,核心替我們執行了類似於我們手動輸入 bash script.sh 的操作。
注意:
#!/前面不能有任何空格。 檔案的第一個字元必須是#,第二個是!。
3. #!/bin/bash 的含義與特性
這是最常見的形式。
#!/bin/bash
含義
- 「這個腳本是 bash 腳本,且
bash位於/bin/bash。」 - 核心在執行此腳本時,總是會執行
/bin/bash。
優點
- 明確性:由於總是使用
/bin/bash,因此很容易預測將使用哪個 bash 版本。 - 效能/簡潔性:直接執行,不需透過
env,因此沒有路徑搜尋的過程。 - 在許多 Linux 發行版中,
/bin/bash實際上被視為「標準位置」。
缺點
-
可能不具可攜性
-
在某些系統上,bash 可能位於不同的路徑,例如
/usr/bin/bash、/usr/local/bin/bash等。 - 有些系統可能根本沒有安裝 bash,只有
/bin/sh。 - 特別是在 macOS, BSD 系列, NixOS, 某些容器環境等系統中,路徑可能有所不同。
4. #!/usr/bin/env bash 的含義與特性
這是目前腳本中常見的形式。
#!/usr/bin/env bash
這裡的關鍵是 /usr/bin/env。
-
env是一個協助「設定/檢查環境變數 + 在 PATH 中搜尋程式」的工具程式。 -
核心實際執行的動作,可以這樣理解:
/usr/bin/env bash script.sh
env會查看系統的PATH環境變數,並在其中尋找並執行bash可執行檔。
優點
- 可攜性高(在多種環境中運作良好)
- 無論 bash 位於
/bin/bash、/usr/bin/bash還是/usr/local/bin/bash, - 只要正確地註冊在 PATH 中,
env就能找到它。
- 使用符合使用者環境的 bash
- 如果使用者自定義了
PATH,並設定優先使用特定版本的 bash,那麼腳本就會使用該版本。
- 在 Python 等語言中也採用相同模式
#!/usr/bin/env python3
缺點
- 前提是
/usr/bin/env必須存在
- 儘管它幾乎存在於所有現代 Unix/Linux 系統中,但在極特殊環境下可能不存在。
- 可能因 PATH 設定而選用不同的直譯器
- 如果 PATH 設定混亂,或者在搜尋路徑中意外地找到了非預期的 bash 版本,可能會執行到錯誤的版本。
- 從安全角度來看,有時需要特別注意
- 在對安全性極為敏感的環境中,人們可能會偏好使用絕對路徑,而不喜歡基於 PATH 來尋找直譯器的方式。
5. 兩種方式比較總結
以下透過簡要比較表進行整理。
| 類別 | #!/bin/bash | #!/usr/bin/env bash |
|---|---|---|
| 直譯器位置指定方式 | 固定絕對路徑 | 透過 PATH 搜尋 |
| 可攜性(系統相容性) | 較低(路徑不同則失效) | 較高(只要 bash 在 PATH 中即可) |
| 使用哪個 bash | 總是 /bin/bash |
在 PATH 中找到的第一個 bash |
| 預期版本保證 | 相對容易 | 可能因 PATH 狀態而異 |
| 安全性/控制力 | 更強(路徑固定) | 略為寬鬆(依賴 PATH) |
| 一般最新趨勢 | 相對舊式風格 | 近來較推薦此方式 |
6. 何時該選擇哪種方式?{#sec-a9bac1ab9ba4}
對於「究竟我該用哪種?」這個問題,我們將根據不同情境進行整理。
1) 個人/團隊開發用腳本(一般開發環境)
- 通常建議使用以下方式:
#!/usr/bin/env bash
-
原因:
-
在開發者直接管理的伺服器、本地環境、CI 環境等中,bash 的位置可能不同。
- 基於 PATH 搜尋並執行更具彈性,且現代的工具/腳本也偏好此方式。
2) 適用於特定伺服器環境的營運腳本
-
例如,若公司內所有伺服器都統一將 bash 安裝在
/bin/bash, -
且伺服器環境相當固定,則:
#!/bin/bash
-
原因:
-
確保始終使用相同的直譯器。
- 可以減少因 PATH 修改而導致的意外行為。
3) 如果真的想讓腳本具備極高的可攜性?
-
如果環境中「可能根本沒有 bash」,那麼 首先應該考慮該腳本是否真的適合依賴 bash。
-
如果可能,請使用
sh編寫:
#!/bin/sh
- 這樣可以在更廣泛的環境中執行。
但請注意,不能使用 bash 特有的語法(如
[[ ]]、陣列、擴展字串處理等)。
7. 使用 #!/usr/bin/env bash 的實用技巧
1) 腳本執行方法
要正確利用 shebang,不應該只這樣做:
bash script.sh # ← 這樣執行 shebang 幾乎沒有意義
建議以下列方式使用:
chmod +x script.sh # 賦予執行權限
./script.sh # 直接執行
這樣核心才會讀取 #!,並使用指定的直譯器。
2) 確認參數傳遞
例如,假設我們建立了一個 test.sh 腳本如下:
#!/usr/bin/env bash
echo "直譯器: $0"
echo "參數: $@"
執行:
chmod +x test.sh
./test.sh hello world
輸出:
直譯器: ./test.sh
參數: hello world
這裡的 $0 是「腳本檔案本身的的路徑」,
只需記住核心實際上是像 /usr/bin/env bash test.sh hello world 這樣執行即可。
8. 常見問題
我曾看過沒有 shebang 的腳本,這是怎麼回事?
-
沒錯,shebang 並非總是必需的。
-
如果像下面這樣直接指定直譯器來執行,則不需要 shebang。即使寫了 shebang 也會被忽略。
bash myscript.sh
python3 myscript.py
- 但是,如果想以下列方式執行,則 shebang 是必需的:
./myscript.sh
./myscript.py
- 特別是對於提供給他人使用的「工具型」腳本,shebang 幾乎可以說是必不可少。
「除了 #!/usr/bin/env,我還看過 #!/bin/env 也能用?」
- 在某些系統上,確實可能存在
/bin/env。 - 然而,通常
/usr/bin/env是更為通用的標準位置。 - 如果沒有特殊理由,使用
#!/usr/bin/env …會更安全。
9. 總結
#!/usr/bin/env bash或#!/bin/bash並非註解,而是告知核心「應使用哪個直譯器來執行此腳本」的指令。-
#!/bin/bash -
總是使用
/bin/bash→ 在固定環境中可預測,但可能不具可攜性 -
#!/usr/bin/env bash -
在
PATH中尋找 bash 並使用 → 更具彈性與可攜性,但會受 PATH 狀態影響 - 在一般的開發/部署環境中,如果以「現代風格」編寫腳本,
則建議將
#!/usr/bin/env bash作為預設選項。

目前沒有評論。