サブシェルで実行されているheredocsでバックスラッシュ改行を保持します。

サブシェルで実行されているheredocsでバックスラッシュ改行を保持します。

ターミナルバックスラッシュがない限り、heredocの出力を変数にキャプチャした後、heredocの改行文字は保持されます。

var=$(cat <<-EOF
a
b
c
EOF
)
echo "$var"

a
b
c

ただし、バックスラッシュ改行文字を保存しようとすると改行文字が失われます。

var=$(cat <<-EOF
a \\
b \\
c
EOF
)

echo "$var"
a \b \c

エスケープの追加にバックスラッシュを追加することは役に立ちません。

もちろん、サブシェルで実行されていない場合は、heredocを使用してバックスラッシュ改行文字で終わる行を生成できます。

$ cat <<-EOF
a \\
b \\
c
EOF
a \
b \
c

この問題を回避するには、改行文字を追加して変数変換を使用して目的の出力を生成できます。

var=$(cat <<-EOF
a \\@
b \\@
c
EOF
)

tr -d '@' <<<"$var"

a \
b \
c

サブシェルで実行されているheredocsでバックスラッシュの改行を維持するより直接的な方法はありますか?

答え1

これがBashのバグなのか(またはバックスラッシュ改行動作が定義されていないのか)疑問に思います。私が試した他のすべてのシェルは、Bashとは異なる動作を表します。

$ cat nl.sh

echo "1:"
cat <<EOF
a \\
b \\
c
EOF

echo "2:"
var=$(cat <<-EOF
a \\
b \\
c
EOF
)
echo "$var"

出力:

$ bash nl.sh
1:
a \
b \
c
2:
a \b \c

そして

$ dash nl.sh
1:
a \
b \
c
2:
a \
b \
c

関数のコマンド置換にコードを入れることができます。これはパーサー関連の問題を解決するのに役立ちます。たとえば、次のようになります。

f() {
cat <<EOF
a \\
b
EOF
}
var=$(f)
echo "$var"

答え2

この文書内で改行拡張を強制する直接的な方法はありません。ただし、ANSIエスケープシーケンス()を使用してエンコードされた改行文字を含み、$'\n'区切り文書内で変数拡張が発生する変数を使用できます。

この形式の異教度拡張では、区切り文字を'EOF'引用符で囲む必要があります。つまり、次のようになります。

nl=$'\n'

その$nl変数を改行文字のプレースホルダとして使用します。

var=$(cat <<-EOF
a $nl
b $nl
c
EOF
)

これで正しく発行されます。

echo "$var"
a 

b 

c

関連情報