介紹如何在 bash shell 指令稿中使用 here document(<<
)與 here string(<<<
)輸入資料。
Linux 中的 here document(<<
)是一種將多行資料直接寫在指令中作為程式輸入的一種指令稿寫法,也常被稱為 heredoc。以下是一個 heredoc 的範例:
# 將文字內容寫入 output.txt cat > output.txt << EOF This is line1 Another line Finally 3rd line EOF
這裡的 EOF
是一個定界符號(delimiter token),用來界定資料的範圍,資料被包裹在兩個定界符號之間,定界符號可以自由替換成任何名稱,只要在資料中沒有出現的字串都可以當成定界符號,例如:
# 不同的定界符號 cat > output.txt << MY_DATA This is line1 Another line Finally 3rd line MY_DATA
實務上可以應用於各種需要輸入多行資料的狀況,例如使用 ssh
連線至遠端執行多行指令時,可以分開執行,也可以用 heredoc 一次輸入多行:
# 分開執行兩行指令 ssh -T office@my.host.com "mv log.txt log.txt.backup" ssh -T office@my.host.com "touch log.txt" # 改用 heredoc 合併兩行指令,一次執行 ssh -T office@my.host.com << EOF mv log.txt log.txt.backup touch log.txt EOF
一般的指令稿程式碼通常為了讓程式碼更容易被閱讀,都會加入 tab 縮排,而遇到 heredoc 的時候,加入 tab 就會造成資料跟原本不同,但是不加 tab 就會破壞程式碼的排版。
這種狀況可以改用 <<-
的方式,忽略所有縮排用的 tab,例如:
# 忽略縮排 Tab cat <<- EOF This is line1 Another line Finally 3rd line EOF
This is line1 Another line Finally 3rd line
在 heredoc 中可以像一般字串一樣插入 shell 變數,例如:
# 插入變數 cat << EOF Hello ${USER} EOF
Hello office
除了變數之外,也可以插入特定指令的執行結果:
# 插入指令執行結果 cat << EOF 現在時間:$(date) EOF
現在時間:一 4月 26 15:59:38 CST 2021
亦可使用反引號的寫法:
# 插入指令執行結果 cat << EOF 現在時間:`date` EOF
現在時間:一 4月 26 16:11:18 CST 2021
heredoc 亦可用來將多個參數傳遞給需要手動輸入資料的指令稿或程式。
舉例來說,假設有一個指令稿 script.sh
的內容如下:
#!/bin/bash read -p "使用者名稱:" username read -p "密碼:" password echo "輸入資料確認:${username} / ${password}"
當這一份指令稿執行時,會需要使用者以鍵盤輸入資料,而我們可以使用 heredoc 的方式將多行資料傳遞給此指令稿:
# 以 heredoc 傳遞多行資料給程式 bash script.sh << EOF office %secret% EOF
輸入資料確認:office / %secret%
在 heredoc 中可以使用反斜線開頭的跳脫字元來輸入一些含有特別意義的字元:
# 使用跳脫字元 cat << EOF 跳脫字元:\$ \\ \` EOF
跳脫字元:$ \ `
若要讓 heredoc 中的字元完全以字面意義來處理,不進行變數或指令的替換,可以使用引號包住定界符號,或是在定界符號前加入反斜線:
# 完全以字面意義來處理資料 cat << "EOF" 跳脫字元:$ \ ` EOF
跳脫字元:$ \ `
# 完全以字面意義來處理資料 cat << 'EOF' 跳脫字元:$ \ ` EOF
跳脫字元:$ \ `
# 完全以字面意義來處理資料 cat << \EOF 跳脫字元:$ \ ` EOF
跳脫字元:$ \ `
heredoc 也可以用來註解多行程式碼,作法是將暫時不用的程式碼以定界符號包起來之後,導向至冒號(:
)這一個虛指令(dummy command):
# 註解多行程式碼 : << EOF echo "這是一行要註解掉的程式碼" echo "這是一行也是" EOF
here string(<<<
)是 heredoc 的簡化版,其不需要定界符號:
# 以 here string 輸入資料 cat <<< "Hello, world."
here string 跟 heredoc 一樣可以插入變數:
# 插入變數 cat <<< "Hello, ${USER}"
Hello, office
在 here string 插入指令執行結果:
# 插入指令執行結果 cat <<< "現在時間:$(date)"
現在時間:一 4月 26 19:03:22 CST 2021
# 插入指令執行結果 cat <<< "現在時間:`date`"
現在時間:一 4月 26 19:03:23 CST 2021
跳脫字元的使用方式也相同:
# 使用跳脫字元 cat <<< "跳脫字元:\$ \\ \`"
跳脫字元:$ \ `