POSIXに "${1-"$var"}"(以下のオプション6)への言及がないのはなぜですか?

POSIXに

私が見つけることができる唯一の参考資料これは仕様です:

「$()」のステートメントと同様に、「囲まれた「${」から一致する「}」までの文字には、二重引用符の影響を受けないでください」などのステートメントを含めることをお勧めします。ただし、System Vシェルの歴史的慣行により、これを防ぐことができます。

明らかな質問は「歴史的な質問は何でしたか」であり、さらに重要なのは、それが今日私たちにどのような影響を及ぼしているのかということです。

C.2.5 Parameters and Variablesこのページのタイトルの下には引用符の拡張の例がたくさんあります。

説明する

問題は、次の6つの引用選択肢の結果に関連しています。

  • $b、、、、"$b"${a-$b}${a-"$b"} "${a-$b}""${a-"$b"}"

最初の5つはPOSIXによって定義され、一部のシェルはこれらの拡張の結果に同意します。一部の値は、次の値に基づいて分割されます$IFS

$ export a=abc; for sh in dash ksh93 bash; do $sh -c 'IFS="bl"; b=value 
  printf "<%s> " 1$b 2"$b" 3${a-$b} 4${a-"$b"} 5"${a-$b}" 6"${a-"$b"}";
  echo'; done

<1va> <ue> <2value> <3a> <c> <4a> <c> <5abc> <6abc> 
<1va> <ue> <2value> <3a> <c> <4a> <c> <5abc> <6abc> 
<1va> <ue> <2value> <3a> <c> <4a> <c> <5abc> <6abc>

しかし、"${1-"$var"}"仕様のどこかに定義されていますか?

つまり、繰り返す二重引用符(外部および内部)

追加1

関連情報で次の結果を見てください。前のコードと次のコードの唯一の違いは、設定されてい$aないことです。

$ unset a; for sh in dash ksh93 bash; do $sh -c 'IFS="bl"; b=value 
  printf "<%s> " 1$b 2"$b" 3${a-$b} 4${a-"$b"} 5"${a-$b}" 6"${a-"$b"}";
  echo'; done

<1va> <ue> <2value> <3va> <ue> <4value> <5value> <6value> 
<1va> <ue> <2value> <3va> <ue> <4value> <5value> <6va> <ue> 
<1va> <ue> <2value> <3va> <ue> <4value> <5value> <6value>

追加2

実際、すべての引用オプションをテストすると、通常のシェルは競合するように動作します。

$ for sh in dash ksh93 bash; do $sh -c 'IFS="bl"; b=value 
  printf "<%s> " 1\n 2"\n" 3${a-\n} 4${a-"\n"} 5"${a-\n}" 6"${a-"\n"}";
  echo'; done

<1n> <2\n> <3n> <4\n> <5\n> <6\n> 
<1n> <2\n> <3n> <4\n> <5\n> <6n> 
<1n> <2\n> <3n> <4\n> <5\n> <6n>

これにはzshも含まれていません!

ベストアンサー1

POSIXではなぜ"${1-"$var"}"言及されないのですか?

拡張子の内側と外側に引用符があることが何を意味するのかは、まったく明確ではないようで、定義されないように承認された変更があるようです。

ただし、拡張の外で引用符を使用するのが一般的です。これは、単語(フィールド)の分割やワイルドカードを防ぐために行うことです。拡張機能に入れることについての言及もあります。

部分2.2.3二重引用符説明する

二重引用符("")で囲まれた文字は、バックティック、<ドル記号>、および<バックスラッシュ>文字を除いて、二重引用符内のすべての文字のリテラル値を保持します。

${[...] 一致する角括弧の文字列で}エスケープされていない偶数の二重引用符または、単一引用符(存在する場合)が必要です。

コマンド置換の場合、次のようになります。

引用符付き文字列の入力文字はおよび間に含まれており、一致$()二重引用符で囲んではいけません。 [...]

パラメータ拡張にはこれに言及していないため、内部文字${...}も外部引用符の影響を受けます。

${foo-\n}対(事例3および5)の例は"${foo-\n}"実際に対。\n同様に、外部引用符がバックスラッシュを保護することを示しています。"\n"


しかし、内部引用文と外部引用文の両方に言及しないようで、何をすべきかは明確ではありません。

内部文字が外部引用符の影響を受ける場合、考えられる説明の1つは最初の内部二重引用符です。終わる参照すると、2番目はそれを再起動してから逆whatever参照します。 Kshは次のようにこの解釈にかなり一貫して従うようです。

$ printf "<%s>\n" "${foo-"foo \n *"}"
<foo>
<n>
<file1.txt>
<file2.txt>

これが非常に役に立つかどうかはわかりませんが、これを行う他のシェルもほとんどありません。 (少なくとも最近試したことと判断した場合。)

<foo \n *>他の例では、文字列が完全に引用されているように、内部二重引用符が単に文字を引用しなければならないという事実を強調するように、出力のほとんどは単なるものです。

その後、BashとDashはバックスラッシュを一貫性のない方法で処理するように見え、印刷は<foo n *>私が考えることができる論理ルールに従わないようです。\n引用されていないかのように動作しますが、*スペースは引用されたかのように動作します。

入れるともっと毛が出ると思います。一つ引用符。


これらの矛盾を目撃しながら、この問題が以前に議論されたのはおそらく驚くべきことではありません。これを明示的に定義されないようにする保留中の変更があるようです。、関連部分は次のとおりです。

サブストリング処理を提供する4つのタイプ以外のパラメーター拡張の場合、拡張が発生する二重引用符は、囲む「$ {」から一致する「}」まで、ストリング内のすべての文字のリテラル値を保持する必要があります。二重引用符、逆引用符および。文字列にエスケープされていない二重引用符文字がある場合、動作は指定されません(組み込みコマンドの置換を除く)。

そして

シェルの実装は、「${...}」内でエスケープされていない二重引用符文字を処理する方法によって大きく異なります(4つの部分文字列処理バリアントを除く)。したがって、標準は動作を指定しません。 [...] "${...}" フォーマット処理の違いにより、System V シェル、BSD、および KornShell 間の歴史的な不一致が発生しました。 POSIX.1-2008のシェルボリュームとユーティリティボリュームのテキストは次のとおりです。あまりにも多くのアプリケーションを中断することなくブレンドを試してください。

これが歴史的な理由のようです。

最初の内容を読む方法は単なる${foo-"bar"}ものではなく、また意味するようです"${foo-"bar"}"。前者はシェル間に異なる結果を与える傾向が少ないようです。

2010年にはこれについての議論は見つかりませんでしたが、単一引用符の仕組みを扱う2016年のメッセージは次のとおりです。

ロバート・エルツ:

引用された${}はシェルの[最も毛深い]部分の1つであり、ある意味で最も恐ろしく再現するのは本当に難しいです。これらすべてが指定されていないか問題になることは驚くべきことではありません8(まだ理解できません)。

チェットレイミ:

さて、Geoffの立場は、Issue 7のテキストがシェルではなくアプリケーションの要件であり、さらに一重引用符と二重引用符のそれぞれの意図について要件があいまいに表現されていることです(つまり、入れ子にすることはできません)。

したがって、解釈221を議論するときに正確であると指摘することができるシェルの動作はなく、議論の一部には何が正しいかを決定し、それを明確に表現することが含まれます。

おすすめ記事