シェル変数でenv
の出力を取得して出力しようとしています。
#!/bin/sh
ENV_BEFORE=$(env)
printf $ENV_BEFORE
その結果、env
出力からの単一の変数が出力されます。
echo
の代わりにprintf
を使用すると、すべての出力が印刷されますが、改行は含まれません。
ここで何が欠けていますか?
問題は、$ENV
変数を引用していないことです。 man bash
で説明されているように:
文字を二重引用符で囲むと、$、 `、\、および履歴拡張が有効な場合は!を除いて、引用符内のすべての文字のリテラル値が保持されます。文字$および `は、二重引用符で囲まれた特別な意味を保持します。 円記号は、$、 `、"、\、またはのいずれかの文字が後に続く場合にのみ、特別な意味を保持します。
したがって、\n
のようなシーケンスを二重引用符で囲むと、その意味が保持されます。これが、引用されていない場合、\n
が通常のn
である理由です。
$ printf \n
n$
一方、引用すると:
$ printf "\n"
$
Bash内の引用符で囲まれていない変数は、split + glob演算子を呼び出します。これは、変数が空白(または特別な変数$IFS
に設定されているもの)で分割され、結果の各Wordがグロブとして使用されることを意味します(一致するファイル名に一致するように展開されます)。あなたの問題は、この「分割」部分にあります。
説明のために、より簡単な複数行変数を見てみましょう。
$ var=$(printf "foo\nbar\n")
これで、シェルのset -x
デバッグ機能を使用して、何が起こっているのかを正確に確認できます。
$ echo $var
+ echo foo bar
foo bar
$ echo "$var"
+ echo 'foo
bar'
foo
bar
上記を見るとわかるように、echo $var
(引用符で囲まれていない)は$var
をsplit + globにサブジェクトするため、2つの別々の文字列foo
とbar
になります。改行は、split + globによって食べられました。変数が引用符で囲まれたとき、それはsplit + globの対象ではなく、改行が保持され、引用符で囲まれているため、正しく解釈され、印刷されます。
次の問題は、printf
がecho
と似ていないことです。それはあなたが与えるものを単に印刷するだけでなく、フォーマット文字列を期待します。たとえば、printf "color:%s" "green"
はgreen
に置き換えられるため、color:green
は%s
を出力します。
また、指定されたフォーマット文字列に収まらない入力は無視されます。したがって、printf foo bar
を実行すると、printf
はfoo
をフォーマット文字列として扱い、bar
はフォーマットする変数として扱います。 bar
に置き換えられる%s
または同等のものがないため、bar
は無視され、foo
のみが出力されます。
$ printf $var
+ printf foo bar
foo
printf $ENV_BEFORE
を実行すると、それが起こりました。変数が引用されていないため、分割グロブは改行をスペースで効果的に置き換え、printf
は最初に見つかった「Word」のみを出力しました。
正しく行うには、フォーマット文字列を使用し、常に変数を引用符で囲みます。
printf '%s\n' "$ENV_BEFORE"
printf
(echo
とは異なり)はデフォルトでは改行を出力しないため、明示的に指定する必要があります。
printf "${ENV_BEFORE}\n"
以上:
printf '%s\n' "$ENV_BEFORE"
@ don_crissti がコメントで正しく指摘された後、もう一度質問を読んだ後、あなたのケースは上記とは異なると思います。
あなたの場合、問題は変数$ENV_BEFORE
を引用していないことです。
変数を引用符で囲まない場合のprintf
とecho
の動作は次のとおりです。
printf
:
引用符と書式指定子がない場合、最初のWordのみが印刷されます
引用符を使用し、フォーマット指定子を使用しない場合、%
をフォーマット指定子として持つ展開のすべてが考慮され、窒息する可能性があります
引用符なしでフォーマット指定子を使用すると、Wordの分割とパス名の展開が行われるため、IFS
の値が出力のスペースになるため、予期しない結果が発生します。
引用符とフォーマット指定子を使用すると、目的の結果が得られます。つまり、展開でWordの分割とパス名の展開は実行されません。
echo
:
引用符がないと、変数の展開はWordの分割とパス名の展開の対象となるため、目的の出力が得られません。
quote
を使用すると、変数の展開はWordの分割やパス名の展開の影響を受けないため、目的の出力が得られます