HEREDOCテキストをPOSIX準拠の方法でシェルスクリプト変数に入れようとしています。私はそうしようとしました:
#!/bin/sh
NEWLINE="
"
read_heredoc2() {
while IFS="$NEWLINE" read -r read_heredoc_line; do
echo "${read_heredoc_line}"
done
}
read_heredoc2_result="$(read_heredoc2 <<'HEREDOC'
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
| | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
HEREDOC
)"
echo "${read_heredoc2_result}"
それは間違った次のものを生み出しました:
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ | | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
以下は機能しますが、ランダムな出力変数を使用することによる不格好さは好きではありません。
#!/bin/sh
NEWLINE="
"
read_heredoc1() {
read_heredoc_first=1
read_heredoc_result=""
while IFS="$NEWLINE" read -r read_heredoc_line; do
if [ ${read_heredoc_first} -eq 1 ]; then
read_heredoc_result="${read_heredoc_line}"
read_heredoc_first=0
else
read_heredoc_result="${read_heredoc_result}${NEWLINE}${read_heredoc_line}"
fi
done
}
read_heredoc1 <<'HEREDOC'
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
| | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
HEREDOC
echo "${read_heredoc_result}"
正しい出力:
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
| | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
何か案は?
問題は、in Bash、$( ... )
エスケープ(およびその他の)シーケンス内で、ヒアドキュメント自体が解析されない場合でも解析されることです。それらを持っている。 \
は改行をエスケープするため、2行になります。あなたが見ているのは本当にBashの解析の問題です-他のシェルはこれを行いません。古いバージョンでは、バックティックが問題になることもあります。私は これがBashのバグであることを確認済み を持っています。これは将来のバージョンで修正される予定です。
少なくとも関数を大幅に簡略化できます。
func() {
res=$(cat)
}
func <<'HEREDOC'
...
HEREDOC
出力変数を選択する場合は、パラメーター化できます。
func() {
eval "$1"'=$(cat)'
}
func res<<'HEREDOC'
...
HEREDOC
または、eval
がないかなり醜いもの:
{ res=$(cat) ; } <<'HEREDOC'
...
HEREDOC
{}
ではなく()
が必要です。これにより、変数は後で利用できるようになります。
これを実行する頻度と目的に応じて、これらのオプションのいずれかを選択できます。最後の1つは、1回限りの場合は最も簡潔です。
zsh
を使用できる場合、元のコマンド置換+ heredocはそのまま動作しますが、これをすべて折りたたむこともできます。
x=$(<<'EOT'
...
EOT
)
Bashはこれをサポートしておらず、あなたが抱えている問題を経験する他のシェルもそうではないと思います。
末尾の改行をサポートするために、@ MichaelHomerからの回答と私の元のソリューションを組み合わせました。最初の1つは魔法の文字列を使用し、最後の2つはPOSIXに準拠していなかったため、@ EliahKaganが指摘したリンクから提案された回避策を使用しませんでした。
#!/bin/sh
NEWLINE="
"
read_heredoc() {
read_heredoc_result=""
while IFS="${NEWLINE}" read -r read_heredoc_line; do
read_heredoc_result="${read_heredoc_result}${read_heredoc_line}${NEWLINE}"
done
eval $1'=${read_heredoc_result}'
}
read_heredoc heredoc_str <<'HEREDOC'
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
| | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
HEREDOC
echo "${heredoc_str}"