為什麼 ls 排序會忽略非字母數字字元?

為什麼 ls 排序會忽略非字母數字字元?

對檔案名稱排序時,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//$LC_ALL中呈現的語言$LANG並尋找其排序規則(例如/usr/share/i18n/locales/*GLibC)並按指示對文字進行排序。

答案3

我對 Debian 的預設排序選項遇到了完全相同的問題,對我來說,它忽略了一個逗號,這阻止了我有效地對 CSV 資料進行排序,從而對我的 AI 造成嚴重破壞。

解決方案是,sort我需要強制排序似乎是的預設行為,而不是單獨使用它-d, --dictionary-order

運行命令:

sort -V

解決我的問題並考慮逗號。

答案4

只是一則評論...我對我的排序規則(es_AR.utf8)有很大的興趣,因為我不能使用'C',因為重音符號,最糟糕的是問題也出現在資料庫postgresql中,在'10之間的句子中'和'10.1'包括(這是一個例子)我不期望的值'100'..我想我必須在每個查詢中使用排序規則..在'10'和'10.Z之間選擇'100' ' 顯示 true 但 SELECT '100' BETWEEN '10' AND '10.Z' COLLATE "C" 顯示 'false' 這是正確的(在我看來)

相關內容