env
シェル変数に出力を取得して印刷しようとしています。
#!/bin/sh
ENV_BEFORE=$(env)
printf $ENV_BEFORE
その結果、env
出力の単一変数が印刷されます。
echo
代わりに使用すると、printf
改行なしですべての出力を印刷します。
私がここで何を見逃しているのでしょうか?
ベストアンサー1
問題は、変数への参照がないことです$ENV
。説明したようにman bash
:
文字を二重引用符で囲むと、履歴拡張が有効になっている場合は、$、`、\、!を除く引用符内のすべての文字のリテラル値が保持されます。 $と `文字は二重引用符の中で特別な意味を持ちます。 バックスラッシュは、$、`、"、\、または文字のいずれかが後に続く場合にのみ特別な意味を維持します。。
したがって、シーケンスを\n
二重引用符で囲むと、その意味が維持されます。そのため、参照がない場合は\n
単に一般的なものですn
。
$ printf \n
n$
そして引用すると:
$ printf "\n"
$
Bashでは、引用符を持たない変数はSplit + glob演算子を呼び出します。これは、変数が空白(または$IFS
特殊変数が設定されているすべての項目)に分割され、各結果単語がglob(一致するファイル名と一致するように拡張)として使用されることを意味します。あなたの問題はその「分割」部分にあります。
これを説明するために、より単純な複数行変数を見てみましょう。
$ var=$(printf "foo\nbar\n")
これで、シェルのset -x
デバッグ機能を使用して、何が起こっているのかを正確に確認できます。
$ echo $var
+ echo foo bar
foo bar
$ echo "$var"
+ echo 'foo
bar'
foo
bar
上に示すように、echo $var
(引用されていない)は分割+globに従うので、2つの別々の文字列とを$var
生成します。改行文字は Split+Glob で食べます。変数が参照されると、分割+globの影響を受けずに改行が維持され、参照されるので正しく解釈され、印刷されます。foo
bar
次の質問はprintf
嫌いですecho
。提供した内容を印刷するだけでなく、書式文字列も必要です。たとえば、次のようにprintf "color:%s" "green"
印刷されます。color:green
%s
green
また、与えられた書式文字列に適合しないすべての入力を無視します。したがって、実行すると、printf foo bar
フォーマット文字列とフォーマットに使用される変数printf
として扱われます。 noまたは同等の項目を置き換えることができるので、無視され、別々に印刷されます。foo
bar
%s
bar
bar
foo
$ printf $var
+ printf foo bar
foo
を実行すると、これが発生しますprintf $ENV_BEFORE
。変数が参照されないので、分割globは効果的に改行を空白に置き換え、最初に見えるprintf
「単語」だけを印刷します。
これを正しく行うには、書式文字列を使用して常に変数を引用します。
printf '%s\n' "$ENV_BEFORE"