ファイル名をソートするときに、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
答え1
編集: 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
これは文字セットとは関係ありません。むしろ、照合順序を決定するのは言語です。libc は、//$LC_COLLATE
で提示された言語を調べ、その照合規則 (GLibC など) を検索し、指示に従ってテキストを順序付けます。$LC_ALL
$LANG
/usr/share/i18n/locales/*
答え3
Debian のデフォルトの並べ替えオプションでもまったく同じ問題が発生しています。私の場合は、無視されているのはコンマで、CSV データを効果的に並べ替えることができず、AI に大混乱を引き起こしています。
解決策としては、sort
単独で使用するのではなく、デフォルトの動作を強制的に並べ替える必要があるようです-d, --dictionary-order
。
次のコマンドを実行します:
sort -V
私の問題を修正し、コンマを考慮します。
答え4
ただのコメントです... 照合順序 (es_AR.utf8) に問題があります。アクセントが de なので 'C' を使用できないからです。さらに最悪なのは、データベース postgresql でも問題が発生することです。その結果、'10' と '10.1' の間の文に (例ですが) 予想外の '100' という値が含まれます。各クエリで照合順序を使用する必要があると思います。SELECT '100' BETWEEN '10' AND '10.Z' は true を示しますが、SELECT '100' BETWEEN '10' AND '10.Z' COLLATE "C" は 'false' を示します。これは正しいです (私の考えでは)