[英]Sorting two files that have the same column gives different sorting
標題很抱歉,但我不知道如何解釋:
我正在嘗試對兩個文件進行排序,因為我想將它們合並,它們看起來像這樣:
test1.txt
rs1010735 224915429
rs1010805 38189142
rs10108 114516330
rs1010863 185432942
rs1010891 110712154
rs1010910 61212213
rs1011124 7533164
和
test2.txt
rs1010735 C
rs1010805 T
rs1010863 T
rs1010891 T
rs10108 C
rs1010910 A
rs1011124 A
我使用sort -k1 test1.txt
和sort -k1 test2.txt
並得到以下信息:
test1_sort.txt
rs1010735 224915429
rs1010805 38189142
rs10108 114516330
rs1010863 185432942
rs1010891 110712154
rs1010910 61212213
rs1011124 7533164
和
test2_sort.txt
rs1010735 C
rs1010805 T
rs1010863 T
rs1010891 T
rs10108 C
rs1010910 A
rs1011124 A
如果前兩列都具有相同的值,為什么會有不同的排序方式。
我也嘗試了sort -n -s k1,1
但是得到了相同的結果。
添加空格:
$ sort -k 1,1 /tmp/2
rs1010735 C
rs10108 C
rs1010805 T
rs1010863 T
rs1010891 T
rs1010910 A
rs1011124 A
$ sort -k 1,1 /tmp/1
rs1010735 224915429
rs10108 114516330
rs1010805 38189142
rs1010863 185432942
rs1010891 110712154
rs1010910 61212213
rs1011124 7533164
這里有兩個問題。
從根本上講,這里的問題是,您正在根據“語言環境”進行排序,該語言環境可能是en_US.UTF-8
(或其他一些Unicode語言環境)。 從理論上講,可識別區域設置的排序將根據該位置的常規排序規則產生預期的排序,而不會感知區域的排序將根據每個字符的“任意”字符代碼進行排序。
例如,在對語言環境敏感的排序中,通常以大寫字母開頭的單詞緊跟在以小寫字母開頭的同一個單詞之前(或之后),而對非語言環境敏感的排序將所有以大寫字母開頭的單詞放在任何以小寫字母開頭的單詞之前。 此外,在講英語的語言環境中,您可能會發現以ä
開頭的單詞與以a
開頭的單詞混合在一起,而在瑞典語的語言環境中,您會在以z
開頭的單詞之后找到它們,因為在瑞典語中, ä
是第28位字母(如果您有興趣,它可以在å之后和ö之前)。
為了使所有工作正常進行,計算機上的語言環境描述需要實際描述每個語言環境中期望的排序順序,尤其是默認語言環境(應與您期望的語言環境相對應)。 從該示例可以看出,有時並非如此。 確實,它有時會產生令人驚訝的意外結果。
在您的示例中發生的是,您的語言環境的語言環境描述指出空白不參與排序 。 它還指示數字在字母之前。 現在,考慮數據的子集(兩個文件合並):
rs10108 114516330
rs1010805 38189142
rs1010863 185432942
rs10108 C
rs1010805 T
rs1010863 T
如果我們完全消除空白,那就是:
rs10108114516330
rs101080538189142
rs1010863185432942
rs10108C
rs1010805T
rs1010863T
然后,如果我們按照正常的字母規則(以數字開頭)對它進行排序,則會得到:
rs101080538189142
rs1010805T
rs10108114516330
rs1010863185432942
rs1010863T
rs10108C
或者,將空格放回原處:
rs1010805 38189142
rs1010805 T
rs10108 114516330
rs1010863 185432942
rs1010863 T
rs10108 C
這些是遵循的規則排序,結果是第一個字段為rs10108
的兩行未一起排序。 違反直覺的,不是嗎?
可能正確的解決方案是告訴任何為您的發行版構建語言環境文件的人,通常的規則是“什么都沒有(可見)在某事之前”,這是我們在學校教過的字母化規則。 換句話說,在任何字符之前都有一個空格(看不見)。 或者,您可以嘗試自己修復歸類文件。
但實際上,解決方案是告訴sort
默認情況下執行非語言環境感知的排序。 我這樣做是:
export LC_COLLATE=C
在我的bash啟動文件中。 ( C
是與編程語言“ C”相對應的語言環境的特殊名稱,其中,符號按其內部字符代碼排序。)您還可以在每次要排序的內容時都鍵入該符號:
LC_COLLATE=C sort test1.txt
-k
參數的含義 要排序的-k
參數具有基本語法:
-k [ , ]
位置的start
位置(以及可選的end
位置)定義了用作排序鍵的文本范圍。 如果未指定end
,則范圍將繼續到該行的末尾。
頭寸的最簡單形式只是一個字段編號,例如1
,表示“第一個字段”。 但是-k1
,因為它的意思是“使用從第一個字段到行尾的文本”,這與說“將整個行用作排序鍵”基本相同,這是默認設置。 因此,每當您看到-k1
您都應該知道它沒有達到預期的效果。
明確指定結尾將更加精確: -k1,1
表示排序鍵是從第一個字段的(開始)到第一個字段的(結束),或者換句話說,第一個字段的文本。 這樣會更好,但不會提供有關如何對具有相同第一字段的兩行進行排序的任何提示。 默認情況下,標准的sort
實用程序不是“穩定的”,因此無法預測將對這兩行進行排序的順序。 通常最好添加更多的二級排序字段:
sort -k1,1 -k2,2
這實際上是“按第一個字段排序,但如果第一個字段相等,則比較第二個字段”。
字段在sort -k1,2
分割(即使將空白忽略以進行排序),因此上述內容與sort -k1,2
不同之處在於,可以確保將具有相同值的行放在連續位置的第一個字段中。
不幸的是, sort -k1,1 -k2,2
也可能不是你想要的東西,特別是如果你做到這一點,在“C”語言環境,因為使用的排序字段的歷史定義的sort
。 除非使用-t
選項指定了明確的定界符,否則排序字段將以每個非空格字符后的空格字符開頭。 因此,除第一個字段外的所有字段都以空格開頭。 如果它們都以相同的空格開頭,那很好,但是通常通過顯式添加正確數量的空格字符來排列字段。 而且這幾乎總是對除第一個字段以外的其他字段產生不正確的排序。
由於通常不需要這樣做,因此sort
提供了一種抑制這種煩人行為的方式: b
sort-key標志(sort key標志位於-k
規范的末尾)。 該標志指示sort
忽略排序鍵中的前導空格。 另外,您可以在將所有排序鍵中指定的任何-k
選項之前都將-b
指定為命令行選項,將其視為具有b
標志。 這表明對sort的正確調用將是:
sort -k1,1 -k2,2b
要么
sort -b -k1,1 -k2,2
有人認為必須一直指定b
令人討厭(因為幾乎總是您想要的),並且向用戶解釋為什么必須這樣做很麻煩。 因此,設置語言環境定義以忽略空白似乎更容易,這肯定會導致忽略主要空白。 該“解決方案”的問題在於,它產生的結果至少令人困惑,因為sort
導致的結果包括字段定義中字段之間的空格,但由於沒有簡單的方法來解決,因此更難解決修改語言環境的排序規則。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.