Shell 中的 Here Document 進階技巧
在 Shell 腳本開發中,我們經常需要處理多行文字輸入,例如生成配置文件、執行 SQL 查詢或建立 Git 提交訊息。雖然 echo 或 printf 能處理簡單輸出,但當內容涉及變數替換、特殊字元或複雜結構時,Here Document(通常簡稱為 Heredoc)便成為了不可或缺的利器。
對於具備基礎 Linux 知識的使用者來說,了解 << 的基本用法只是第一步。本文將深入探討 Heredoc 的進階技巧,幫助你寫出更簡潔、健壯的腳本。
基本回顧與變數替換
Here Document 的基本語法是使用 << 後接一個分隔符(Delimiter),通常為 EOF。Shell 會讀取直到遇到該分隔符為止的所有內容,並將其作為標準輸入傳遞給命令。
預設情況下,Heredoc 會進行變數替換(Variable Expansion)和命令替換(Command Substitution)。這意味著你可以直接在多行內容中嵌入 $VARIABLE 或 `command`。
#!/bin/bash
NAME="Ubuntu"
VERSION="22.04"
cat <<EOF
正在安裝 $NAME $VERSION...
系統資訊:$(uname -r)
EOF
執行結果會正確顯示替換後的值。然而,這種預設行為在某些情境下反而是麻煩的來源。
進階技巧一:禁用變數替換
當你需要將程式碼片段(如 Python 或 SQL 代碼)原封不動地輸出,而不希望 Shell 誤判其中的 $ 或其他特殊字元時,必須對分隔符進行「引用」。
只需將分隔符用單引號 '' 或雙引號 "" 包起來,即可禁用變數替換。
#!/bin/bash
PYTHON_CODE='print("Hello World")'
# 如果不加引號,Shell 會嘗試尋找 $PYTHON_CODE 變數,導致錯誤或空值
cat <<'PYTHON_SCRIPT'
import sys
def greet(name):
print(f"Hello, {name}!")
if __name__ == "__main__":
greet("Linux User")
PYTHON_SCRIPT
在這個範例中,<<'PYTHON_SCRIPT' 確保了內部內容被視為純文字,完美保留 Python 的語法結構。這是撰寫動態生成腳本時最常用的技巧。
進階技巧二:使用縮排與 Trim 功能
在結構複雜的 Shell 腳本中,Heredoc 的內容通常會與程式碼邏輯縮排對齊,以保持可讀性。然而,這會導致生成的內容包含不必要的空白字元。
從 Bash 4.0+ 開始,你可以在分隔符前加上連字號 -,即 <<-。這允許 Shell 忽略行首的 Tab 字元(注意:僅限 Tab,空格無效),從而自動「修剪」縮排。
#!/bin/bash
# 定義一個函數來生成 JSON 結構
generate_json() {
cat <<-JSON
{
"name": "example",
"status": "active",
"config": {
"debug": true
}
}
JSON
}
# 執行並格式化輸出
echo "$(generate_json)" | python3 -m json.tool
注意: 為了讓 <<- 生效,Heredoc 內容的每一行開頭必須使用 Tab 字元進行縮排。如果在編輯器中設定為使用空格縮排,此功能將無效。請確保你的編輯器支援 Tab 字元,或在執行前檢查檔案內容。
進階技巧三:多行輸入與管道結合
Heredoc 不僅能與 cat 搭配,還能與任何接受標準輸入的命令結合,例如 ssh、awk 或 grep。這對於遠端執行命令或數據處理極為有用。
#!/bin/bash
# 範例:在遠端伺服器執行複雜的 awk 指令
REMOTE_HOST="192.168.1.10"
ssh -o StrictHostKeyChecking=no "$REMOTE_HOST" <<'REMOTE_CMD'
# 這裡的內容會直接在遠端伺服器執行
df -h | awk 'NR>1 {print $1, $5}' | grep -v "^$"
REMOTE_CMD
此技巧避免了在本地構建長串 SSH 指令的複雜性,並確保命令在正確的上下文中執行。
常見問題與解決方案
1. 為什麼 <<- 無法去除空格?
如前所述,<<- 僅處理 Tab 字元。許多現代編輯器預設使用空格進行縮排,這會導致 <<- 失效。
解決方案:
- 在編輯器中切換到 Tab 模式。
- 或者,不使用
<<-,而是手動使用sed或awk在後處理中移除前導空格,例如:cat <<EOF | sed 's/^ //'。
2. 分隔符名稱可以任意選擇嗎?
是的,分隔符可以是任何不與內容衝突的字串。建議使用有意義的名稱,如 SQL、PYTHON、JSON,以提高可讀性。
注意事項:
- 分隔符必須獨立成行,前後不能有空白字元(除非使用
<<-)。 - 避免使用 Shell 關鍵字或特殊字元作為分隔符,以免引起解析錯誤。
小結
Heredoc 是 Shell 腳本中處理多行文字的精簡工具。通過掌握變數替換的開關(引用分隔符)、縮排修剪(<<-)以及與管道的結合,你可以大幅提升腳本的靈活性和可維護性。下次在撰寫需要生成複雜配置或代碼的腳本時,不妨試試這些進階技巧,讓你的工作流更加順暢。