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. 核心如何執行腳本?

將執行過程極度簡化後,大致如下:

  1. 使用者執行具備執行權限的腳本
chmod +x script.sh
./script.sh
  1. 核心讀取 script.sh
  2. 檢查檔案的前兩個字元是否為 #!
  3. 如果符合,則將該行的其餘部分
  • 識別為「解釋器路徑 + 參數」
  • 並執行該程式,同時將腳本檔案路徑作為參數傳遞

例如,如果 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 執行檔並加以執行。

優點

  1. 具備可移植性 (在多種環境下運作良好)

    • 無論 bash 位於 /bin/bash/usr/bin/bash 還是 /usr/local/bin/bash
    • 只要它正確地註冊在 PATH 中,env 就能找到它。
  2. 使用符合使用者環境的 bash

    • 如果使用者自訂了 PATH,將特定版本的 bash 設定為優先使用,那麼腳本就會依此使用該版本的 bash。
  3. Python 等語言也採用相同模式

    ```python

    !/usr/bin/env python3

    ```

缺點

  1. /usr/bin/env 必須存在的前提

    • 雖然幾乎所有現代 Unix/Linux 系統都具備此工具,但在極為特殊的環境中可能不存在。
  2. 可能因 PATH 設定而使用到不同的解釋器

    • 如果 PATH 設定混亂,或意外地優先找到非預期的 bash 版本,可能會執行到不希望使用的版本。
  3. 在安全考量下需特別留意

    • 在對安全性極為敏感的環境中,有時會傾向使用絕對路徑來指定解釋器,以避免依賴 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 作為預設選項
shebang 在 Linux 腳本中的運作原理圖
shebang 在 Linux 腳本中的運作原理圖