bashの予期しない文字に一致するブラケット式(範囲なし)


20

Linuxでbashを使用しています。次のifステートメントから成功していますが、これは失敗コードを返すべきではありませんか?

if [[  = [⅕⅖⅗] ]] ; then echo yes ; fi

正方形はどの文字とも等しくないため、成功コードを取得する理由がわかりません。

私の場合、二重括弧を保持することが重要です。

このシナリオで範囲を実行する他の方法、または他に何か提案はありますか?


2
おそらく、これらのすべての文字がロケールで未定義のソート順を持っている(したがって同じようにソートする)結果です。オースティングループで進行中の関連する議論をご覧ください。ロケールをCに変更して修正します。
ステファンシャゼル

1
申し訳ありませんが、Cシングルバイト文字ではないため、ここでは実行しません。C.UTF-8利用可能な場所で行います。
ステファンシャゼル

11
おめでとうございます、あなたは最初の質問でオースティングループのスレッドを振り回すステファンを召喚することができました。それはインターネットの少なくとも⅗の価値があるはずです。または⅘またはインターネット■明らかにそれらは同じです。Unix&Linuxへようこそ。引き続き興味深い質問をお寄せください。
デロバート

回答:


29

これは、これらの文字が同じ並べ替え順序を持っているためです。

また、それに気づくでしょう

sort -u << EOF




EOF

1行のみを返します。

またはその:

expr  = 

(POSIXで要求されるように)trueを返します。

GNUシステムに同梱されているほとんどのロケールには、同じ並べ替え順序を持つ多数の文字(および文字のシーケンス(照合シーケンス)もあります)があります。これらの■⅕⅖⅗のものの場合、それは順序が定義されておらず、順序が定義されていない文字がGNUシステムで同じソート順序を持つことになります。sortingやlikeのように同じソート順を持つと明示的に定義されている文字があります(ただし、実際のロジックやその方法に関する一貫性は明らかではありませんが)。

それは非常に驚くべき、偽の行動の原因です。私はごく最近、オースティングループ(POSIXおよびSingle UNIX Specificationの背後にある団体)メーリングリストでこの問題提起しましたが、2015-04-03の時点でまだ議論が続いています。

この場合は、どうか[y]と一致する必要がありxどこxy同じを並べ替える私には不明であるが、ブラケット表現は、ことを示唆している照合要素、一致することを意図しているので、bash動作が期待されているが。

いずれにせよ、[⅕-⅕]少なくとも[⅕-⅖]一致する必要があります。

さまざまなツールの動作が異なることに気付くでしょう。ksh93振る舞うようbashGNU、grepまたはsedしないでください。他のいくつかのシェルにはyash、さらにバグが多いような異なる動作があります。

一貫した動作を実現するには、すべての文字のソートが異なるロケールが必要です。Cロケールは典型的なものです。ただし、ほとんどのシステムのCロケールの文字セットはASCIIです。GNUシステムでは、通常C.UTF-8、UTF-8文字で作業する代わりに使用できるロケールにアクセスできます。

そう:

(export LC_ALL=C.UTF-8; [[  = [⅕⅖⅗] ]])

または標準的な同等物:

(export LC_ALL=C.UTF-8
 case  in ([⅕⅖⅗]) true;; (*) false; esac)

falseを返す必要があります。

別の選択肢はLC_COLLATE、GNUシステムで動作するC のみに設定することですが、マルチバイト文字のソート順の指定に失敗する可能性がある他のシステムでは必ずしもそうではありません。


その教訓の1つは、文字列の比較に関して、平等は期待するほど明確な概念ではないということです。平等とは、最も厳しいものから最も厳しいものまでを意味する場合があります。

  1. 同じバイト数とすべてのバイト構成要素は同じ値を持ちます。
  2. 同じ文字数とすべての文字は同じです(たとえば、現在の文字セットの同じコードポイントを参照します)。
  3. 2つの文字列の並べ替え順序は、ロケールの照合アルゴリズムと同じです(つまり、a <bもb> aもtrueではありません)。

現在、2または3の場合、両方の文字列に有効な文字が含まれていると想定しています。UTF-8およびその他のエンコーディングでは、バイトのシーケンスによっては有効な文字が形成されません。

そのため、またはいくつかの文字が複数の可能なエンコーディングを持っている可能性があるため、1と2は必ずしも同等ではありません。これは通常、ISO-2022-JPのようなステートフルエンコーディングの場合だAと表現することができる411b 28 42 411b 28 42私はかかわらず、違いをすることはありませんスイッチにシーケンスでASCIIにし、あなたが望むようにそれらの多くとして挿入することができ、)これらのタイプのエンコーディングがまだ使用中であるとは思わないでしょうし、GNUツールは少なくともそれらと一緒に正しく動作しません。

また、ほとんどの非GNUユーティリティは0バイト値(ASCIIのNUL文字)を処理できないことに注意してください。

これらの定義のどちらが使用されるかは、ユーティリティとユーティリティの実装またはバージョンによって異なります。POSIXはそのことについて完全に明確ではありません。Cロケールでは、3つすべてが同等です。そのYMMVの外。


1と2が異なるもう1つの一般的なケースは、文字の組み合わせなどのUnicodeの場合です。
ジル「SO-悪であるのをやめる」

@Gilles、結合文字は独自の文字です。この組み合わせは、書記素/セルを形成しますが、いくつかの文字で構成されています。é(U + 00E9)とé(eにU + 0301が続く)は同じ書記素ですが、2つの異なる文字シーケンス(少なくともPOSIX APIの観点から)です。1と2で、それらは異なります。U + 0301のすべての照合ウェイトが「IGNORE」に設定されている場合、3人までは同じと見なすことができますが、一般に発音区別記号の順序を決定する場合はそうではありません。
ステファンシャゼル

通常、同じ文字列を考慮éて同じ文字列にすることが望ましいですが、ではありませんe。POSIXの照合順序の概念はめったに正しくなく、文字に基づいているため、文字列の並べ替えのほとんどの一般的な方法を考慮していません次にアクセントを使用して関係を決定します)。
ジル「SO-悪であるのをやめる」

@Gilles、はい。だからこそ、glibcロケールで(意図的に)同じ並べ替え順序を持つ文字はほとんど意味がありません。évséは通常、正規分解のように最初に文字列に何らかの変換を行うことで対処されます(大文字と小文字を区別しないソート/マッチングを行う場合、最初に小文字に変換するのに似ています)。このテーマに関するいくつかの適切なリファレンスについては、ICUガイドも参照してください。
ステファンシャゼル

@ Gilles、POSIXロケール照合アルゴリズムの重みは、フランス語の辞書ソートを実行できます。それが重みの仕組みです。最初のパスは、一次重みを使用して(等しい場合)チェックアクセント、第3パス総額...第二のパス(E及びE(E及びE)が同じと組み合わせ急性アクセントは無視さを有する場合)
ステファンChazelasを

-3

あなたは間違ったことをやって、さ===同じではありません。

これらの例を試してください:

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi

1
それは真実ではない。POSIXは、演算子=を使用して同等性をチェックすることを指定します。問題は、演算子ではなく引用符の欠落です。
scai

1
またman bash[[セクションでは、「=演算子は==と同等です」とも述べています。
michas

1
@ scai、POSIXは[[...]]演算子を指定しません。また、=および==は、実装されているシェル(ksh / bash / zsh)およびパターンマッチング用であり、同等ではありません。
ステファンシャゼル

パターンと比較する場合、パターンは引用符で囲む必要があります。引用符で囲まない場合、リテラル文字列と見なされるため、最初のテストでは「no」となります。
xhienne
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.