printf は 1 行だけ印刷します。

printf は 1 行だけ印刷します。

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の影響を受けずに改行が維持され、参照されるので正しく解釈され、印刷されます。foobar

次の質問はprintf嫌いですecho。提供した内容を印刷するだけでなく、書式文字列も必要です。たとえば、次のようにprintf "color:%s" "green"印刷されます。color:green%sgreen

また、与えられた書式文字列に適合しないすべての入力を無視します。したがって、実行すると、printf foo barフォーマット文字列とフォーマットに使用される変数printfとして扱われます。 noまたは同等の項目を置き換えることができるので、無視され、別々に印刷されます。foobar%sbarbarfoo

$ printf $var
+ printf foo bar
foo

を実行すると、これが発生しますprintf $ENV_BEFORE。変数が参照されないので、分割globは効果的に改行を空白に置き換え、最初に見えるprintf「単語」だけを印刷します。

これを正しく行うには、書式文字列を使用して常に変数を引用します。

printf '%s\n' "$ENV_BEFORE"

おすすめ記事