lsソートで英数字以外の文字が無視されるのはなぜですか?


25

ファイル名をソートするとき、などのls文字を無視します-,_。ソートにもこれらの文字を使用することを期待していました。

例:

touch a1 a2 a-1 a-2 a_1 a_2 a.1 a.2 a,1 a,2

ここでこれらのファイルを表示しますls -1

a1
a_1
a-1
a,1
a.1
a2
a_2
a-2
a,2
a.2

私が期待したのは次のようなものでした:

a1
a2
a,1
a,2
a.1
a.2
a_1
a_2
a-1
a-2

つまり、ソート時に英数字以外の文字が考慮されることを期待していました。

誰もこの行動を説明できますか?この動作は標準で義務付けられていますか?または、これはエンコーディングがUTF-8であるためですか?

更新:これはUTF-8ソートに関連しているようです:

$ LC_COLLATE=C ls -1
a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

2
UTF-8とASCIIは、使用しているのが最初の128コードポイント(例)だけである場合は同一です。するとどうなりますかLC_COLLATE=C ls
Alexios

問題は、ASCIIとUTF-8が同一であることではなく、UTF-8が独自の照合(ソート)ルールを持っていることです。
ダニエルクルマン

1
はい、[_-,.]グループ化され、何らかの形で半無視されているのは事実です。単に、とだけに照合変化するので、私はそのような照合が定義されている正確にどのようにかどこかわからないが、それは照合の問題でなければなりませんCを(経由するLC_COLLATE=C ls -l)と仮定すると(あなたが期待されるソート順を与えるのに十分ですLC_ALLオーバーライドしないLC_COLLATE)。これは、Unicode Basic Multilingual Planeの全範囲の文字に
当てはまり

動作が気に入らない場合は、エイリアスを作成して〜/ .profileに入れることができます
。alias

回答:


10

これは文字セットとは関係ありません。むしろ、照合順序を決定するのは言語です。libcは$LC_COLLATE/ $LC_ALL/で提示された言語を調べ、$LANGその照合規則(/usr/share/i18n/locales/*GLibCなど)を検索し、指示に従ってテキストを順序付けます。


参考:これよりも複雑です。strcollたとえば、使用する場合は、aasa.c上記のように並べ替えられることがわかりますaas.c
ドンスコット

12

編集:LC_COLLATE = Cでソートされたデータのテストを追加


デフォルトの照合シーケンスは、それらの「句読点タイプ」文字を等しい値であるとしてUse LC_COLLATE=C処理します.. それらをコードポイント順に処理します..

for i in 'a1' 'a_1' 'a-1' 'a,1' 'a.1' 'a2' 'a_2' 'a-2' 'a,2' 'a.2' ;do
  echo $i; 
done |LC_COLLATE=C sort

出力

a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

次のコードは、すべてのテストの有効な基本多言語面でのUTF-8文字を(を除いて、\ X00\ X0A、簡単にするために)
それはランダムに並べ替えられ、そのファイルに対して、知られている(生成)昇順にファイルを比較し、その後で再びソートLC_COLLATE = C。結果は、Cシーケンスが元の生成されたシーケンスと同一であることを示しています。

{ i=0 j=0 k=0 l=0
  for i in {0..9} {A..F} ;do
  for j in {0..9} {A..F} ;do
  for k in {0..9} {A..F} ;do
  for l in {0..9} {A..F} ;do
     (( 16#$i$j$k$l == 16#0000 )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l == 16#000A )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#D800    && 
        16#$i$j$k$l <= 16#DFFF )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#FFFE )) && { printf '.' >&2; continue; }
     echo 0x"$i$j$k$l" |recode UTF-16BE/x4..UTF-8 || { echo "ERROR at codepoint $i$j$k$l " >&2; continue; } 
     echo 
  done
  done
  done; echo -n "$i$j$k$l " >&2
  done; echo >&2
} >listGen

             sort -R listGen    > listRandom
LC_COLLATE=C sort    listRandom > listCsort 

diff <(cat listGen;   echo "last line of listOrig " ) \
     <(cat listCsort; echo "last line of listCsort" )
echo 
cmp listGen listCsort; echo 'cmp $?='$?

出力:

63485c63485
< last line of listOrig 
---
> last line of listCsort

cmp $?=0

2
それはどこに文書化されていますか?その部分はUnicode標準の一部ですか?
ダニエルクルマン

2
実際、それらは同じ値を取得しません。これらの文字はソート時に単に無視されます。それらが等しい値を持つものとして扱われた場合、ソート順a_1 a2 a_2は不可能になります。
ダニエルクルマン

あなたのハードワークとサンプルコードのために+1。ディレクトリ名を句読点で並べ替えて方法に合わせたtree後、比較文字列から句読点が削除されるなど、ストーリーにはもっと多くのことがあると思います。/文字は、照合シーケンスの最下位の文字として設定する必要があると言えます。
WinEunuuchs2Unix
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.