介紹如何在 bash shell 指令稿中使用 here document(<<)與 here string(<<<)輸入資料。
Here Document
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
一般的指令稿程式碼通常為了讓程式碼更容易被閱讀,都會加入 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
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 <<< "跳脫字元:\$ \\ \`"
跳脫字元:$ \ `
參考資料
- StackExchange:What’s the difference between «, «< and < < in bash?
- Baeldung:Here Document And Here String
- Linux Shell Scripting Tutorial (LSST) v2.0:Here strings
- Linux Shell Scripting Tutorial (LSST) v2.0:Here documents
- Advanced Bash-Scripting Guide:Here Documents
- Advanced Bash-Scripting Guide:Here Strings
