>>二重山かっこを使って行をソートする方法は?

>>二重山かっこを使って行をソートする方法は?

sort次のような行で奇妙に振る舞うようです。>>b

$ cat test
a
>>b
b
c
>
>>

$ sort test
>
>>
a
b
>>b
c

私はその>>b行が出力の3番目の行になると予想していましたが、sort5番目の行です。なぜこれが起こり、sort予想される結果を得る方法がありますか?

私はGNU / Linux Ubuntu 16.04を使用しています。

答え1

現代言語環境のソートアルゴリズムは非常に複雑です。

各キャラクター(実際には要素の構成複数の文字のシーケンスで構成できます (例: Czech ch)。重みの設定ソート順序を決定します。

2つの文字列を比較するときは、すべての文字の最初の重みが最初に使用され、次に他の重みを使用して、2つの文字列が最初の重みと等しく揃っていることを確認します。

たとえば、多くのロケールでは、eéE同じです。基本的な重み(同じ同等クラスに属し、両方が一致します[=e=])。

echoしたがって、たとえば、étéとをEnter最初のパスで比較すると、デフォルトの重みは同じで、e2番目の文字は順序(before before)を決定します。éEcnt

最初のパス以降été、、、と比較するとÉté同じランクが割り当てられるため、2番目のパスに2次重みを適用します。Ete一般的なGNUロケールでは、ラテンスクリプト文字の2番目の重みがアクセントの優先順位を決定するために使用されます(アクセントのないもの、次のイエス、アクセントのあるもの、ブレベ、ミュートなど)。次に、été合計を決定するために3番目の重みを使用する必要があります。Étéこれは大文字と小文字に基づいています(ほとんどのロケールでは小文字から始まります)。体重も同じなのでランクも同じキャラクターもいます。

これは、人間と同様に、辞書と同じ方法でテキストをソートするために使用されます。

辞書では、スペースやほとんどの句読点も無視されることがわかります。たとえば、との間de factodebut並べ替えますdevoid。空白文字の最初の重みはIGNOREです。

/usr/share/i18n/locales/iso14651_t1_commonGNUシステムでは、定義されたコア照合順序を見つけることができます(パスはディストリビューションによって異なります)。そこから以下を見ることができます:

ifdef UPPERCASE_FIRST
<CAP>
else
<MIN>
endif
[...]
ifdef UPPERCASE_FIRST
[...]
<MIN> # 10
[...]
else
[...]
<CAP> # 9
[...]
endif

[...]
order_start <SPECIAL>;forward;backward;forward;forward,position
<U0020> IGNORE;IGNORE;IGNORE;<U0020> # 32 <SP>
[...]
<U003E> IGNORE;IGNORE;IGNORE;<h> # 140 >
[...]
ifdef DIACRIT_FORWARD
order_start <LATIN>;forward;forward;forward;forward,position
else
order_start <LATIN>;forward;backward;forward;forward,position
endif
[...]
<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U00E9> <e>;<ACA>;<MIN>;IGNORE # 260 é
[...]
<U0045> <e>;<BAS>;<CAP>;IGNORE # 577 E
<U00C9> <e>;<ACA>;<CAP>;IGNORE # 578 É

これは私たちが言ったことを示しています。スペースと>最初の3つの重みはすべてに設定されますIGNORE。最初の3つの重みが等しくソートされた文字列の場合にのみ、相対順序(>スペースの前、<h>未指定の組み合わせシンボルの前にリストされている<U0020>)が考慮されます。

定義されたロケールUPPERCASE_FIRST(たとえば/usr/share/i18n/locales/tr_TR)では、大文字が最初に表示されます(3番目のパスでDIACRIT_FORWARD一部のロケールと同様に、de_DE2番目のパスでは発音区別記号の順序を逆に決定できます。

>パス1、2、3でも同じ位置合わせ行います。 4番目の項目では、空の文字列がすべての項目よりも前に並べ替えられます。>>>>>

>>bそれ以降にソートしてください。b最初の3つのパスでは同じようにソートされていますが、b4番目のパスでは無視され、>サイズが大きいためです。c最初のパス(>無視および前)bより少ない。cアイデアを得ることができます。

Cさて、ロケール定義を見てください。はるかに簡単です。重みは1つだけで、U+0000からU+10FFFFまでのコードポイント値に基づいています。したがって、SPC(U + 0020)は>(U + 003E)の前に並べられ、(U + 003E)はb(U + 0062)の前に整列され、(U + 0063)はc(U + 0063)の前に整列されます。どんなキャラクターも見落とされません。

少なくともGNU libcの場合、比較関数(strcoll()したがって使用される共同)が含まれる場合、sortCロケール定義ファイルで定義された順序は無視されます。の値に関係なく、LC_CTYPEおよびはと同じLC_COLLATE=Cです。比較は常にバイト値に基づいているため、そのバイトがUnicodeコードポイントが反対方向に並べられた文字に対応していても(たとえば、ISO-8859-15の0xA4 U + 20AC EURO SIGN対A5 U + 00A5 YEN SIGN)文字セット)と(他に設定されていない場合)は同じ効果を持ちます。strcoll()strcmp()LC_ALL=C sortLC_COLLATE=C sortLC_ALL

答え2

sort(1)マニュアルページから:

   *** WARNING *** The locale specified by the  environment  affects  sort  order.   Set
   LC_ALL=C to get the traditional sort order that uses native byte values.

したがって、バイト値でソートするには、次のようにします。

LC_ALL=C sort test

それ以外のsort場合、ソート可能なキーが見つかるまで先行文字は無視されます。これがまさに>>bそのb隣にある理由です。

関連情報