$(echo ...)を使用しない限り、forループでIFSシェル変数を設定して文字列を単語に分割するのはどうですか?

$(echo ...)を使用しない限り、forループでIFSシェル変数を設定して文字列を単語に分割するのはどうですか?

設定により、文字列が、およびの3つの単語に分割されると仮定IFS='X'します。bashfooXbarXbazfoobarbaz

forただし、コマンド置換によって文字列がループに提供されている場合にのみ機能します$(echo fooXbarXbaz)

$ IFS='X'; for x in fooXbarXbaz; do echo Y${x}Z; done
Yfoo bar bazZ
$ IFS='X'; for x in $(echo fooXbarXbaz); do echo Y${x}Z; done
YfooZ
YbarZ
YbazZ

最初の例のコマンドは3つのfooXbarXbaz単語に分割されませんが、2番目の例では成功する理由を誰かが説明できますか?

答え1

$IFS引用符のない拡張噴射にのみ使用されます。には拡張子がありませんfor x in fooXbarXbaz。ただし、引用符のない拡張があります。これは、および3つの引数で呼び出されるというecho Y${x}Z意味です。ユーティリティは、各引数の間にスペースを入れて印刷するので。echoYfoobarbazZechoYfoo bar bazZ

2番目の例では、文字列は拡張であるコマンド置換の出力であるため、文字列はループ用に分割されています。

この変数はユーティリティへの入力をIFS分割するためにも使用されます。read

答え2

fooXbarXbaz最初のコマンド例を3つの単語に分割できない理由を誰かが説明できますか?

シェルはこのように動作しないのでもっと

いくつかの古代では、噴射は次のような簡単な言葉でも発生しました。heirloom-sh:

heirloom-sh$ for foo in 123o456o789; do echo $foo; done
ech: not found
ech: not found
ech: not found

こんにちは、私の言葉は次のようになりました。

heirloom-sh$ for foo in 123o456o789; do "echo" $foo; done
123
456
789

(キーワードと変数名はosで区切られません。)

oor Xinを使用するのはIFSやや極端ですが、現在の最良のシナリオは、分割が次にのみ発生することです。拡大する

*意図的に分割を使用する場合は、引用符のない拡張もワイルドカード処理を実行するため、このような状況が発生する可能性があることに注意してください。配列は通常、複数の値を処理するのに適しています。

答え3

GNU bashドキュメントはこの動作を明確に説明しています。コマンドの置き換え

二重引用符内で置換が発生すると、結果に対して単語の区切りやファイル名の拡張は行われません。

2番目のケースには引用符のない代替項目があるため、fooXbarXbazシェルはset値に基づいて結果文字列をトークン化してIFS単語を複数の単語に分割します。

最初のケースでは、for x in fooXbarXbaz;文字列はパス名拡張(グローバル拡張とも呼ばれます)を通過します。シェルは、すべての可能な拡張が完了した後、語彙よりもはるかに後の段階でこれを行います(参照)シェル拡張)、結果の文字列は文字通り処理されます。

パス名拡張の前に発生する変数拡張ケースを追加するには、$varOPと同じプロセスを実行します。

IFS='X'; var=fooXbarXbaz; for x in $var; do echo Y${x}Z; done

引用符のない変数拡張(コマンドの置換など)は、値に基づいて単語分割を実行しますIFS。これが、私たちがシェルによる予期しないトークン化を避けるために、一般的にすべての拡張を引用しなければならないと主張する理由です。

関連情報