出力を変数に代入するときにコマンド置換を引用する必要がありますか? [コピー]

出力を変数に代入するときにコマンド置換を引用する必要がありますか? [コピー]

出力が変数に割り当てられても、次のようにコマンド置換を引用する傾向があります。

var="$(command)"

しかし、これは本当に必要ですか?いつ壊れるの?受け入れられた回答ここ主張する:

DIRNAME="$(ディレクトリ名$FILE)"欲しいことはしない$FILE の空白またはワイルドカード文字 [?*。

このリンクはGrey Cat Wikiの引用に関する素晴らしいページにリンクされていますが、そのページでは引用コマンドの置き換えについて特に言及していません。そして引用しながら変える明らかに必要ですが、quoteコマンドの置き換え自体は必要ないようです。

しかし、同じ記事では、次のように結論を下しました。

DIRNAME="$(dirname "$FILE")" が推奨される方法です。他のものを変更せずにDIRNAME =をコマンドとスペースに置き換えることができ、dirnameは正しい文字列を受け取ります。

これは私がいつも考えてきたもので、ここで言及されていない投稿をしばしば修正することです。ただし、上記のWikiページには次のような主張もあります。

場合によっては、二重引用符を安全に省略できます。

単純課題の右側にあります。引用符なしでfoo = $ barを書くことができます。これはPOSIXと互換性があります。

[。 。 。 ]

これは実際には「簡単な」割り当てではありませんが、var=$(command)実際に引用が必要な場合はまだ見つかりません。

$ var=$(echo "foo bar baz")  ## whitespace works
$  echo "$var"
foo bar baz

$ var=$(printf "foo\nbar * baz") ## so do globbing characters
$ echo "$var"
foo
bar * baz

$ var1="foo\nbar * baz"
$ var=$(printf "$var1")  ## printing a variable doesn't make any difference
$ echo "$var" 
foo
bar * baz

$ var=$(printf '%s\n' "$var1")
$ echo "$var"
foo\nbar * baz

$ var=$(printf -- '-e %s\n' "$var1") ## strings starting with - also work
$ echo "$var"
-e foo\nbar * baz

もちろん、そのようなものに直接コマンド置換を使用するなら引用command1 "$(command2)"符は必ず必要ですが、変数に割り当てるときにはそうではありません。

それでは、私が何を見逃しているのでしょうか?見積もりが必要ですか?どの特別なケースがコマンド置換を呼び出すのですか?戻り値を変数に割り当てるときあなたを保護しますか?あるいは、コマンド置換が変数代入操作の右側である場合、コマンド置換を引用しなくても常に大丈夫ですか?

答え1

あなたはそうです不要代入文の右側の式を参照します。

あなたをいじめるのは別の答えですおすすめそれにもかかわらず。しかし、これはコードメンテナンスに関するものです。

以下を考慮してください正しい例:

DIRNAME=$(dirname "$FILE")
echo "debug: dirname is $DIRNAME"
ls "$DIRNAME"

このスクリプトをしばらく使用したら、デバッグメッセージを削除できると思います。したがって、エディタを使用するとエコーラインを削除できます。これにより、DIRNAME変数が不要になることがわかります。ls割り当てられた左側のサイトを置き換えるコマンドを移動するだけです。今できる必要な引用符を追加するのを忘れました。君はこれで終わるんだ壊れたスクリプト:

ls $(dirname "$FILE")

最初の作成者がシェルの専門家であり、2番目の編集者が初心者の場合、これらのエラーが発生する可能性が高くなります。

もちろんこれが議論の余地があるのか​​?ポータブルシェル機能を使用しないことをお勧めします。本当に便利です。個人的に私は主に彼のアドバイスに従います。また、次のように、より簡単な割り当てのためにこれを行います。 (var="${foo}"追加の中括弧も含みます。)

答え2

参考資料の一つとして、Bashのマニュアルはこれを非常に明確に述べています。:

次の形式のステートメントを使用して変数を割り当てることができます。

name=[value]

値を指定しないと、変数に空の文字列が割り当てられます。すべての値には、チルダ拡張、パラメータおよび変数拡張、コマンド置換、算術拡張、および引用符の削除があります(詳細は以下を参照)。 [...]単語分割を行わない、以下のように「$@」は除外されます。ファイル名拡張は行われません。

単語の区切りやファイル名の拡張がないため、引用符は必要ありません。


POSIXの場合2.9.1 簡単なコマンド:

2.変数ではなく割り当てまたはリダイレクトである単語は拡張する必要があります。拡張後もフィールドが残っている場合、最初のフィールドはコマンド名として扱われる必要があり、残りのフィールドはコマンドの引数です。
[...]
4.チルダ拡張、パラメータ拡張、コマンド置換、算術拡張、および引用符の削除を割り当てる前に、すべての変数割り当てを拡張する必要があります。

フィールド分割が手順2で行われた拡張でのみ発生すると解釈する必要があるかどうかはわかりません。ステップ4を実行いいえフィールド分割が言及されていますが、関連部分はフィールド分割マルチフィールド生成の例外として、変数の割り当てに関する言及もありません。

関連情報