[Special Parameters[( http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02 ) ] の POSIX 仕様セクションで見つけます。
@
1 から始まる定位置パラメーターに展開されます。展開が二重引用符内で発生し、フィールド分割 (フィールド分割を参照) が実行される場合、各位置パラメーターは個別のフィールドとして展開されます。元の単語 (展開されたパラメーターが単語内に埋め込まれていると仮定)、最後のパラメーターの展開は元の単語の最後の部分と結合されます。位置パラメータがない場合、'@' が二重引用符で囲まれている場合でも、'@' の展開によってゼロ フィールドが生成されます。
*
1 から始まる定位置パラメーターに展開されます。二重引用符で囲まれた文字列 (二重引用符を参照) 内で展開が発生すると、各パラメーターの値が IFS 変数の最初の文字で区切られた単一のフィールドに展開されるか、IFS が設定されていない場合は a で展開されます。IFS がヌル文字列に設定されている場合、これは設定を解除することと同じではありません。最初の文字が存在しないため、パラメーター値が連結されます。
したがって、引用されたバリアントから始めます(より単純です):
*
展開が「IFS変数の最初の文字で区切られた各パラメーターの値を持つ単一のフィールドに[s]を展開する」ことがわかります。これがとa|b
から得られる理由です。echo "${X[*]"
log2 "${X[*]}"
@
また、「各位置パラメーターは個別のフィールドとして展開される」ように展開が展開されることもわかります。これがとa b
から得られる理由です。echo "${X[@]}"
log2 "${X[@]}"
仕様テキストのフィールド分割に関する注記を見ましたか? 「フィールド分割 (フィールド分割を参照) が実行される場所」? ここが謎の鍵です。
引用符の外では、展開の動作は同じです。違うのはその後の展開です。具体的には、フィールド/単語の分割です。
問題を示す最も簡単な方法は、コードをset -x
有効にして実行することです。
これで次のようになります。
+ X=(a b)
+ IFS='|'
+ echo a b
a b
+ echo a b
a b
+ echo a b
a b
+ echo 'a|b'
a|b
+ echo ---
---
+ log1 a b
+ echo a b
a b
+ log1 a b
+ echo a b
a b
+ log1 a b
+ echo a b
a b
+ log1 'a|b'
+ echo a b
a b
+ echo ---
---
+ log2 a b
+ echo a b
a b
+ log2 a b
+ echo a b
a b
+ log2 a b
+ echo a b
a b
+ log2 'a|b'
+ echo 'a|b'
a|b
ここで注意すべきことはlog1
、最後のケース以外のすべてで が呼び出されるまでに、|
はすでになくなっているということです。
すでになくなっている理由は、引用符がないと、変数展開の結果(この場合は*
展開) がフィールド/単語分割になるためです。そして、拡張されたフィールドを結合するためと、それらを再度分割するための両方IFS
に使用されるため、フィールド分割によって飲み込まれます。|
そして、説明を終了するために(実際に問題になっている場合)、log1
呼び出しで展開の引用されたバージョン(つまり、正しくlog1 "${X[*]}"
展開される)でもこれが失敗する理由は、それ自体が展開の引用された展開を使用しないためです。関数内のof自体が単語分割されています (その場合と他のすべての場合で見られるように)。log1 "a|b"
log1
@
@
echo a b
log1
log1