Linux 腳本首行之謎:#!/usr/bin/env bash 與 #!/bin/bash 究竟是什麼?
在 Linux 中撰寫腳本時,我們習慣性地會在開頭寫上這兩行指令。
#!/usr/bin/env bash
或者
#!/bin/bash
從表面上看,它就像一行註解… 但這一行的真實身份究竟是什麼?它們之間又有哪些區別呢? 本文將帶您深入了解這行指令的意義,並探討在什麼情境下應該選擇哪種寫法。
1. 這不是註解:什麼是 shebang?
以 #! 開頭的這一行指令,我們稱之為 shebang。
#!/bin/bash
在 Shell 看來,由於它以 # 開頭,確實很像「註解」。
然而,對於作業系統(核心)而言,它並非註解,而是:
「這是一個指示,告訴核心應該使用哪個解釋器程式來執行此腳本。」
換句話說,
#!/bin/bash→ 「請使用/bin/bash來執行此檔案。」#!/usr/bin/env bash→ 「請透過env尋找bash解釋器,並使用它來執行此檔案。」
2. 核心如何執行腳本?
將執行過程極度簡化後,大致如下:
- 使用者執行具備執行權限的腳本
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 中搜尋程式」。 -
您可以將核心實際執行的操作理解為這樣:
bash
/usr/bin/env bash script.sh
env會檢查系統的PATH環境變數,並在其中尋找bash執行檔並加以執行。
優點
-
具備可移植性 (在多種環境下運作良好)
- 無論 bash 位於
/bin/bash、/usr/bin/bash還是/usr/local/bin/bash, - 只要它正確地註冊在
PATH中,env就能找到它。
- 無論 bash 位於
-
使用符合使用者環境的 bash
- 如果使用者自訂了
PATH,將特定版本的 bash 設定為優先使用,那麼腳本就會依此使用該版本的 bash。
- 如果使用者自訂了
-
Python 等語言也採用相同模式
```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. 何時該選擇哪種寫法?
針對「我到底該用哪種?」這個問題,我們將依據不同情境進行整理。
1) 個人用 / 團隊開發用腳本 (一般開發環境)
- 通常建議使用以下寫法:
bash
#!/usr/bin/env bash
-
理由:
-
在開發者自行管理的伺服器、本地環境、CI 環境中,bash 的位置可能不同。
- 基於 PATH 搜尋執行更具彈性,且現代工具/腳本多數偏好此方式。
2) 專用於特定伺服器環境的營運腳本
-
例如,如果公司內所有伺服器都統一將 bash 安裝在
/bin/bash, -
且伺服器環境相對固定,則可以考慮使用:
bash
#!/bin/bash
-
理由:
-
確保始終使用相同的解釋器。
- 減少因 PATH 修改而導致的非預期行為。
3) 如果希望腳本具備最大程度的可移植性?
-
如果是在「可能完全沒有 bash」的環境下, 那麼首先應該思考此腳本是否適合依賴 bash。
-
如果可能,請使用
sh來撰寫腳本:
bash
#!/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,也會被忽略。
bash
bash myscript.sh
python3 myscript.py
- 但是,如果您希望像這樣執行腳本,那麼 shebang 則是必不可少的:
bash
./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作為預設選項。
