Linux文件排序工具 sort 命令详解
sort是排序工具,它完美貫徹了Unix哲學(xué):"只做一件事,并做到完美"。它的排序功能極強(qiáng)、極完整,只要文件中的數(shù)據(jù)足夠規(guī)則,它幾乎可以排出所有想要的排序結(jié)果,是一個(gè)非常優(yōu)質(zhì)的工具。
雖然sort很強(qiáng)大,但它的選項(xiàng)很少,使用方法也很簡(jiǎn)單。更讓人覺(jué)得它成功的地方在于:即使想要實(shí)現(xiàn)復(fù)雜、完整的sort功能,所使用的選項(xiàng)和一般使用時(shí)的選項(xiàng)沒(méi)什么不同。只不過(guò)要實(shí)現(xiàn)復(fù)雜功能時(shí),必須得理解sort是如何工作的。
也就是說(shuō),沒(méi)搞懂sort工作機(jī)制時(shí),它也能完成任務(wù),指哪就能打哪,但沒(méi)被指到的地方難免會(huì)有所偏差和疑惑。只有搞懂了sort機(jī)制,才能真正的指哪打哪,結(jié)果中一絲偏差也沒(méi)有,即使出現(xiàn)了偏差也知道是為什么。
本文先解釋sort命令的常用選項(xiàng),再給出sort的簡(jiǎn)單使用示例,用于初步解釋sort各選項(xiàng),最后對(duì)sort深入說(shuō)明。更完整的選項(xiàng)說(shuō)明可參考info sort的譯文:sort命令中文手冊(cè)(info sort翻譯)。
1.1 選項(xiàng)說(shuō)明
sort讀取每一行輸入,并按照指定的分隔符將每一行劃分成多個(gè)字段,這些字段就是sort排序的對(duì)象。同時(shí),sort可以指定按照何種排序規(guī)則進(jìn)行排序,如按照當(dāng)前字符集排序規(guī)則(這是默認(rèn)排序規(guī)則)、按照字典排序規(guī)則、按照數(shù)值排序規(guī)則、按照月份排序規(guī)則、按照文件大小格式(k<M<G)。還可以去除重復(fù)行,指定降序或升序(默認(rèn))的排序方式。
默認(rèn)的排序規(guī)則為字符集排序規(guī)則,通常幾種常見(jiàn)字符的順序?yàn)椋?空字符串<空白字符<數(shù)值<a<A<b<B<...<z<Z",字典排序規(guī)則也如此。
語(yǔ)法格式:
sort [OPTION]... [FILE]... 選項(xiàng)說(shuō)明: -c:檢測(cè)給定的文件是否已經(jīng)已經(jīng)排序。如未排序,則會(huì)輸出診斷信息,提示從哪一行開(kāi)始亂序。 -C:類(lèi)似于"-c",只不過(guò)不輸出任何診斷信息。可以通過(guò)退出狀態(tài)碼1判斷出文件未排序。 -m:對(duì)給定的多個(gè)已排序文件進(jìn)行合并。在合并過(guò)程中不做任何排序動(dòng)作。 -b:忽略字段的前導(dǎo)空白字符。空格數(shù)量不固定時(shí),該選項(xiàng)幾乎是必須要使用的。"-n"選項(xiàng)隱含該選項(xiàng)。 -d:按照字典順序排序,只支持字母、數(shù)值、空白。除了特殊字符,一般情況下基本等同于默認(rèn)排序規(guī)則。 --debug:將顯示排序的過(guò)程以及每次排序所使用的字段、字符。同時(shí)還會(huì)在最前幾行顯示額外的信息。 -f:將所有小寫(xiě)字母當(dāng)成大寫(xiě)字母。例如,"b"和"B"是相同的。 :在和"-u"選項(xiàng)一起使用時(shí),如果排序字段的比較結(jié)果相等,則丟棄小寫(xiě)字母行。 -k:指定要排序的key,key由字段組成。key格式為"POS1[,POS2]",POS1為key起始位置,POS2為key結(jié)束位置。 -n:按數(shù)值排序。空字符串""或""被當(dāng)作空。該選項(xiàng)除了能識(shí)別負(fù)號(hào)"-",其他所有非數(shù)字字符都不識(shí)別。 :當(dāng)按數(shù)值排序時(shí),遇到不識(shí)別的字符時(shí)將立即結(jié)束該key的排序。 -M:按字符串格式的月份排序。會(huì)自動(dòng)轉(zhuǎn)換成大寫(xiě),并取縮寫(xiě)值。規(guī)則:unknown<JAN<FEB<...<NOV<DEC。 -o:將結(jié)果輸出到指定文件中。 -r:默認(rèn)是升序排序,使用該選項(xiàng)將得到降序排序的結(jié)果。 :注意:"-r"不參與排序動(dòng)作,只是操作排序完成后的結(jié)果。 -s:禁止sort做"最后的排序"。 -t:指定字段分隔符。 :對(duì)于特殊符號(hào)(如制表符),可使用類(lèi)似于-t$' '或-t'ctrl+v,tab'(先按ctrl+v,然后按tab鍵)的方法實(shí)現(xiàn)。 -u:只輸出重復(fù)行的第一行。結(jié)合"-f"使用時(shí),重復(fù)的小寫(xiě)行被丟棄。
1.2 sort示例
此小節(jié)為sort的簡(jiǎn)單用法示例,也是平時(shí)最可能用上的示例。如果只是為了使用sort,而不是為了刨根問(wèn)題,本小節(jié)已經(jīng)足夠。
假設(shè)當(dāng)前已有文件system.txt,內(nèi)容如下:其中空白部分為單個(gè)制表符。
[root@linuxidc tmp]# cat system.txt 1 mac 2000 500 2 winxp 4000 300 3 bsd 1000 600 4 linux 1000 200 5 SUSE 4000 300 6 Debian 600 200
(1).不加任何選項(xiàng)時(shí),將對(duì)整行從第一個(gè)字符開(kāi)始依次向后直到行尾按照默認(rèn)的字符集排序規(guī)則做升序排序。
[root@linuxidc tmp]# sort system.txt 1 mac 2000 500 2 winxp 4000 300 3 bsd 1000 600 4 linux 1000 200 5 SUSE 4000 300 6 Debian 600 200
由于每行的第一個(gè)字符1<2<3<4<5<6,所以結(jié)果如上。
(2).以第三列為排序列進(jìn)行排序。由于要?jiǎng)澐肿侄危灾付ㄗ侄畏指舴V付ㄖ票矸@種無(wú)法直接輸入的特殊字符的方式是$' '。
[root@linuxidc tmp]# sort -t $' ' -k3 system.txt 4 linux 1000 200 3 bsd 1000 600 1 mac 2000 500 2 winxp 4000 300 5 SUSE 4000 300 6 Debian 600 200
結(jié)果中雖然1000<2000<4000的順序是對(duì)了,但600卻排在最后面,因?yàn)檫@是按照默認(rèn)字符集排序規(guī)則進(jìn)行排序的,字符6大于4,所以排最后一行。
(3).對(duì)第三列按數(shù)值排序規(guī)則進(jìn)行排序。
[root@linuxidc tmp]# sort -t $' ' -k3 -n system.txt 6 Debian 600 200 3 bsd 1000 600 4 linux 1000 200 1 mac 2000 500 2 winxp 4000 300 5 SUSE 4000 300
結(jié)果中600已經(jīng)排在第一行。結(jié)果中第2行、第3行的第三列值均為1000,如何決定這兩行的順序?
(4).在對(duì)第3列按數(shù)值排序規(guī)則排序的基礎(chǔ)上,使用第四列作為決勝屬性,且是以數(shù)值排序規(guī)則對(duì)第四列排序。
[root@linuxidc tmp]# sort -t $' ' -k3 -k4 -n system.txt 6 Debian 600 200 4 linux 1000 200 3 bsd 1000 600 1 mac 2000 500 2 winxp 4000 300 5 SUSE 4000 300
如果想在第3列按數(shù)值排序后,以第2列作為決勝列呢?由于第2列為字母而非數(shù)值,所以下面的語(yǔ)句是錯(cuò)誤的,雖然得到了期望的結(jié)果。
[root@linuxidc tmp]# sort -t $' ' -k3 -k2 -n system.txt 6 Debian 600 200 3 bsd 1000 600 4 linux 1000 200 1 mac 2000 500 2 winxp 4000 300 5 SUSE 4000 300
之所以最終得到了正確的結(jié)果,是因?yàn)?strong>默認(rèn)情況下,在命令行中指定的排序行為結(jié)束后,sort還會(huì)做最后一次排序,這最后一次排序是對(duì)整行按照完全默認(rèn)規(guī)則進(jìn)行排序的,也就是按字符集、升序排序。由于1000所在的兩行中的第一個(gè)字符3小于4,所以3排在前面。
之所以說(shuō)上面的語(yǔ)句是錯(cuò)誤的,是因?yàn)榈?列第一個(gè)字符是字母而不是數(shù)值,在按數(shù)值排序時(shí),字母是不可識(shí)別字符,一遇到不可識(shí)別字符就會(huì)立即結(jié)束該字段的排序行為。可以使用"--debug"選項(xiàng)來(lái)查看排序的過(guò)程和排序時(shí)所使用的列。注意,該選項(xiàng)只有CentOS7上的sort才有。
[root@linuxidc tmp]# sort --debug -t $' ' -k3 -k2 -n system.txt
sort: using ‘en_US.UTF-8’ sorting rules
sort: key 1 is numeric and spans multiple fields
sort: key 2 is numeric and spans multiple fields
6>Debian>600>200
___ # 第1次排序行為,即對(duì)"-k3"排序,此次用于排序的字段為第3列
^ no match for key # 第2次排序行為,即對(duì)"-k2"排序,但顯示無(wú)法匹配排序key
________________ # 默認(rèn)sort總會(huì)進(jìn)行最后一次排序,排序?qū)ο鬄檎?3>bsd>1000>600
____
^ no match for key
______________
4>linux>1000>200
____
^ no match for key
________________
1>mac>2000>500
____
^ no match for key
______________
2>winxp>4000>300
____
^ no match for key
________________
5>SUSE>4000>300
____
^ no match for key
_______________
(5).在對(duì)第3列按數(shù)值排序規(guī)則排序的基礎(chǔ)上,使用第2列作為決勝屬性,且以默認(rèn)排序規(guī)則對(duì)此列降序排序。
[root@linuxidc tmp]# sort -t $' ' -k3n -k2r system.txt 6 Debian 600 200 4 linux 1000 200 3 bsd 1000 600 1 mac 2000 500 2 winxp 4000 300 5 SUSE 4000 300
由于既要對(duì)第3列按數(shù)值升序排序,又要對(duì)第2列按默認(rèn)規(guī)則降序排序,因此只能對(duì)每個(gè)字段單獨(dú)分配選項(xiàng)。注意,雖然"r"選項(xiàng)是降序結(jié)果,但它不影響排序過(guò)程,只影響最終排序結(jié)果。也就是說(shuō),在按照升序排序結(jié)束得到最終結(jié)果后,再反轉(zhuǎn)第2列順序,也就是得到了降序的結(jié)果。同樣也說(shuō)明,sort在排序的時(shí)候,一定且只能按照升序排序,只有排序動(dòng)作結(jié)束了"r"選項(xiàng)才開(kāi)始工作。
緊跟在字段后的選項(xiàng)(如"-k3n"的"n"和"-k2r"的"r")稱(chēng)為私有選項(xiàng),使用短橫線寫(xiě)在字段外的選項(xiàng)(如"-n"、"-r")為全局選項(xiàng)。當(dāng)沒(méi)有為字段分配私有選項(xiàng)時(shí),該排序字段將繼承全局選項(xiàng)。當(dāng)然,只有像"-n"、"-r"這樣的排序性的選項(xiàng)才能繼承和分配給字段,"-t"這樣的選項(xiàng)則無(wú)法分配。
因此,"-n -k3 -k4"、"-n -k3n -k4"和"-k3n -k4n"是等價(jià)的,"-r -k3n -k4"和"-k3nr -k4r"是等價(jià)的。
實(shí)際上,上面的命令寫(xiě)法并不嚴(yán)謹(jǐn)。更標(biāo)準(zhǔn)的寫(xiě)法應(yīng)該如下:
sort -t $' ' -k3n -k2,2r system.txt
"-k2,2"表示排序?qū)ο髲牡?個(gè)字段開(kāi)始到第2個(gè)字段結(jié)束,也就是限定了只對(duì)第二個(gè)字段排序。它的格式為"POS1,POS2",如果省略POS2,將自動(dòng)擴(kuò)展到行尾,即"-k2"等價(jià)于"-k2,4",也就是說(shuō),對(duì)整個(gè)第2列到第4列進(jìn)行排序。
需要注意,由于上面的"-k2"繼承了全局默認(rèn)的排序規(guī)則,即按字符排序而非按數(shù)值排序,此時(shí)它能夠等價(jià)于"-k2,4",但如果是"-k2n"按照數(shù)值排序的話(huà),它不等價(jià)于"-k2,4n"或"-k2n,4n"或"-k2n,4"(這3者為等價(jià)寫(xiě)法),之所以不等價(jià),是因?yàn)榘磾?shù)值排序時(shí)只能識(shí)別數(shù)字和負(fù)號(hào)"-",當(dāng)排序時(shí)遇到其他所有字符,都將立即結(jié)束此次排序。所以"-k2n"等價(jià)于"-k2,2n"或"-k2n,2"或"-k2n,2n"。
這些理論性的知識(shí)點(diǎn),請(qǐng)參照下一小節(jié)sort的理論內(nèi)容。后文也不再解釋理論性的內(nèi)容,只是介紹命令使用方法。
(6).在對(duì)第3列按數(shù)值排序規(guī)則排序的基礎(chǔ)上,使用第2列的第2個(gè)字符作為決勝屬性,且以默認(rèn)排序規(guī)則對(duì)此列升序排序。
[root@linuxidc tmp]# sort -t $' ' -k3n -k2.2,2.2 system.txt 6 Debian 600 200 4 linux 1000 200 3 bsd 1000 600 1 mac 2000 500 2 winxp 4000 300 5 SUSE 4000 300
其中"-k2.2,2.2"表示從第2個(gè)字段的第2個(gè)字符開(kāi)始,到第2個(gè)字段的第2個(gè)字符結(jié)束,即嚴(yán)格限定為第2個(gè)字段第2個(gè)字符。如果需要對(duì)此字符降序排序,則"-k2.2,2.2r"。
(7).使用"-u"去除重復(fù)字段所在的行。例如第3列有兩行1000,兩行4000,去除字段重復(fù)的行時(shí),將只保留排在前面的第一行。
[root@linuxidc tmp]# sort -t $' ' -k3n -u system.txt 6 Debian 600 200 3 bsd 1000 600 1 mac 2000 500 2 winxp 4000 300
由于需要去除重復(fù)字段的行,因此使用"-u"時(shí)將禁止sort做"最后一次排序"。至于字段重復(fù)的行中,如何判斷哪一行是排在最前面的行,需要搞懂sort的整個(gè)工作機(jī)制,請(qǐng)通讀本文。
"sort -u"和"sort | uniq"是等價(jià)的,但是如果多指定幾個(gè)選項(xiàng),它們將不等價(jià)。例如,"sort -n -u"只會(huì)檢查排序字段數(shù)值部分的唯一性,但"sort -n | uniq"在sort對(duì)行中字段按數(shù)值排序后,uniq將檢查整個(gè)行的唯一性。
(8).將排序結(jié)果保存到文件中。即可以使用重定向,也可以使用"-o"選項(xiàng),但使用重定向不可保存到原文件,因?yàn)樵趕ort開(kāi)始執(zhí)行前,原文件先被重定向截?cái)唷6褂?-o"則沒(méi)有這樣的問(wèn)題,因?yàn)閟ort在打開(kāi)文件前先完成數(shù)據(jù)的讀取。但"-o"和"-m"一起使用時(shí),同樣不安全。
[root@linuxidc tmp]# sort -t $' ' -k3n -o system1.txt system.txt
(9).使用"-c"或"-C"檢測(cè)文件是否排過(guò)序。如果已排序,則不返回任何信息,退出狀態(tài)碼為0。如果未排序,退出狀態(tài)碼為1,但"-c"會(huì)給出診斷信息,并指明從哪一行開(kāi)始亂序,而"-C"不返回任何信息。
[root@linuxidc tmp]# sort -c -k3n system.txt ;echo $? sort: system.txt:3: disorder: 3 bsd 1000 600 1
說(shuō)明system.txt中的第3行開(kāi)始出現(xiàn)亂序,且退出狀態(tài)碼為1。
[root@linuxidc tmp]# sort -C -k3n system.txt ;echo $? 1
1.3 深入研究sort
咋一看上去,sort的使用方法很簡(jiǎn)單,不就是"sort -t DELIMITER -k POS1,POS2 file"嗎,確實(shí)如此,它的man文檔也才100來(lái)行,連info文檔加上一堆廢話(huà)也才500多行。但事實(shí)上,sort命令很難,也可以說(shuō)很簡(jiǎn)單,簡(jiǎn)單是因?yàn)椴还苁菑?fù)雜功能還是簡(jiǎn)單功能,用來(lái)用去就那么幾個(gè)選項(xiàng),難是因?yàn)闆](méi)搞懂它的工作機(jī)制和細(xì)節(jié)時(shí),有些時(shí)候的結(jié)果會(huì)比較出人意料,也不知道為什么會(huì)如此。
本小節(jié)主要講理論和工作機(jī)制的細(xì)節(jié),偶爾給出幾個(gè)示例,所以遇到疑惑時(shí)請(qǐng)自行測(cè)試,當(dāng)然也歡迎在博客下方留言。另外,"--debug"(CentOS7才支持該選項(xiàng))選項(xiàng)對(duì)排疑解惑有極大幫助,所以應(yīng)該善用該選項(xiàng)。
(1).sort命令默認(rèn)按照字符集的排序規(guī)則進(jìn)行排序,可以指定"-d"選項(xiàng)按照字典順序排序,指定"-n"按照數(shù)值排序,指定"-M"按照字符格式的月份規(guī)則排序,指定"-h"按照文件容量大小規(guī)則排序。
字符集排序規(guī)則和字典排序規(guī)則對(duì)能識(shí)別的字符來(lái)說(shuō),順序一般是一致的,幾種常見(jiàn)字符的順序?yàn)椋?空字符串<空白字符<數(shù)值<a<A<b<B<...<z<Z"。
指定不同的排序規(guī)則,不僅改變排序時(shí)的依據(jù),還間接影響排序時(shí)的行為,因?yàn)椴煌判蛞?guī)則能夠識(shí)別的字符類(lèi)型不同。至于如何影響,見(jiàn)下面的(4)。
(2).sort使用"-t"選項(xiàng)指定的分隔符對(duì)每行進(jìn)行分割,得到多個(gè)字段,分隔符不作為字段的內(nèi)容。默認(rèn)的分隔符為空白字符和非空白字符之間的空字符,并非網(wǎng)上眾多文章所說(shuō)的空格或制表符(原文:By default, fields are separated by the empty string between a non-blank character and a blank character.)。
例如," foo bar"默認(rèn)將分隔為兩個(gè)字段" foo"和" bar",而使用空格作為分隔符時(shí)將分隔為三個(gè)字段:第一個(gè)字段為空,第二個(gè)字段和第三個(gè)字段為"foo"和"bar"。使用下面三個(gè)sort語(yǔ)句可以驗(yàn)證默認(rèn)的分隔符并非空格。
[root@linuxidc ~]# echo -e " 234 bar 123 car" | sort -t ' ' -b -k3 234 bar 123 car [root@linuxidc ~]# echo -e " 234 bar 123 car" | sort -b -k2 234 bar 123 car [root@linuxidc ~]# echo -e " 234 bar 123 car" | sort -b -k3 # -k3指定的字段超出了范圍,所以key為空 123 car 234 bar
(3).使用"-k"選項(xiàng)指定排序的key。不指定排序key時(shí),整行將成為排序key,即對(duì)整行進(jìn)行排序。
key由字段組成,格式為"POS1,[POS2]",表示每行排序的起始和終止位置。也就是說(shuō),key才是排序的對(duì)象。
POS的格式為"F[.C][OPTS]",其中F表示字段的序號(hào),C表示該字段中字符的序號(hào)。字段和字符的位置都從1開(kāi)始計(jì)算。如果POS2的字符位置指定為0,則表示POS2字段中的最后一個(gè)字符。如果POS1中省略".C",則默認(rèn)值為1(字段的起始字符),如果POS2中省略".C",默認(rèn)值為0(字段的終止字符)。使用"-b"選項(xiàng)忽略前導(dǎo)空白字符時(shí),C從第一個(gè)非空白字符開(kāi)始計(jì)算。如果F或C超出了有效范圍,則該key為空,例如一行只有3個(gè)字段,卻指定了"-k4",或者第2字段只有3個(gè)字符,卻指定了"-k2.5"。
如果省略POS2,則key將自動(dòng)擴(kuò)展到行尾,即等價(jià)于"POS1,line_end"。如果不省略POS2,則該key可能會(huì)跨越多個(gè)字段。無(wú)論那種情況,跨越多個(gè)字段時(shí),key中會(huì)保留字段間的分隔符。
OPTS指定的是該key的選項(xiàng),包括但不限于"bfnrhM",它們的作用和全局選項(xiàng)"-b"、"-f"、"-n"、"-r"、"-h"、"-M"相同。默認(rèn)情況下,如果key中沒(méi)有指定任何OPTS,則該key會(huì)繼承全局選項(xiàng)。當(dāng)key中單獨(dú)指定了選項(xiàng)時(shí),這些選項(xiàng)是該key的私有排序選項(xiàng),將覆蓋全局選項(xiàng)。除了"b"選項(xiàng)外,其余選項(xiàng)無(wú)論是指定在POS1還是POS2中都是等價(jià)的,對(duì)于"b"選項(xiàng),指定在POS1則作用于POS1,指定在POS2則作用于POS2。如果繼承了全局選項(xiàng)"-b",則作用于POS1和POS2。
字段前數(shù)量不固定的前導(dǎo)空白字符,將使得字段混亂,因此強(qiáng)烈建議總是忽略前導(dǎo)空白字符。數(shù)值排序時(shí)(即"n"選項(xiàng))隱含"b"選項(xiàng)。
可以使用多個(gè)"-k"選項(xiàng)指定多個(gè)key,排序時(shí)將按照key的順序進(jìn)行排序。第一個(gè)key通常稱(chēng)為主排序key(primary key)。第二個(gè)key將在第一個(gè)key排序的基礎(chǔ)上排序,同理,第三個(gè)key將在第二個(gè)key的排序基礎(chǔ)上進(jìn)行排序。
以下是幾個(gè)例子:例子中出現(xiàn)了選項(xiàng)"n"的,描述暫不嚴(yán)謹(jǐn),但目前只能如此描述,在稍后的(4)中解釋。
"-k 2":因?yàn)闆](méi)有指定POS2,所以key擴(kuò)展到了行尾。因此該key從第2字段第一個(gè)字符開(kāi)始,到行尾結(jié)束。
"-k 2,3":該key從第2字段第一個(gè)字符開(kāi)始到第3字段最后一個(gè)字符結(jié)束。
"-k 2,2":該key僅擁有第2字段。
"-k 2,3n"和"-k 2n,3"和"-k 2n,3n":這三者等價(jià),因?yàn)槌?b"選項(xiàng),OPTS指定在POS1或POS2的結(jié)果是一樣的。
"-k 2,3b"和"-k 2b,3"和"-k 2b,3b":這三者互不等價(jià)。
"-k 2n":該key從第2字段開(kāi)始直到行尾,都按數(shù)值排序。
"-k 2.2b,3.2n":該key從第2字段的第2個(gè)非空白字符開(kāi)始,到第3字段第2字符(可能包含空白字符)結(jié)束,且該key按照數(shù)值排序。其實(shí)此處的b選項(xiàng)是多余的,因?yàn)閚隱含了b選項(xiàng)。
"-k 5b,5 -k 3,3n":定義了兩個(gè)排序key,主排序key為第5字段不包含空白字符的部分,副key為第三個(gè)字段。主key按照默認(rèn)規(guī)則排序,副key按照數(shù)值排序。副key在主key排序后的基礎(chǔ)上再排序。
"-k 5,5n -k 3b,6b":主key為第5字段,按照數(shù)值排序,副key從第3字段到第六字段,忽略前導(dǎo)空白字符,但是按照默認(rèn)規(guī)則排序。副key在主key排序后的基礎(chǔ)上再排序。
(4).當(dāng)排序規(guī)則選項(xiàng)(例如"n"、"d"、"M"、"h")發(fā)現(xiàn)不識(shí)別的符號(hào)時(shí),將立即結(jié)束當(dāng)前key的排序。默認(rèn)排序規(guī)則是字符集的排序規(guī)則,通常能識(shí)別所有字符,所以總會(huì)對(duì)整個(gè)key進(jìn)行完整的排序。這是"何時(shí)跨字段、跨key比較?"的問(wèn)題。
例如,指定n選項(xiàng)按數(shù)值排序時(shí),由于"n"選項(xiàng)只能識(shí)別數(shù)字和負(fù)號(hào)"-",當(dāng)排序時(shí)遇到無(wú)法識(shí)別字符時(shí),將導(dǎo)致該key的排序立即結(jié)束。也就是說(shuō),對(duì)于"abc 123 456 abc"這樣的輸入,分隔符為空格,當(dāng)指定"-k 2,3n"時(shí),雖然排序key包括"123 456",但由于中間的空白字符無(wú)法被n識(shí)別,使得在排完第2字段"123"時(shí)就立即結(jié)束該key的排序。
正因如此,使得n選項(xiàng)絕對(duì)不會(huì)跨字段、跨key進(jìn)行比較。因此,"-k 2,3n"和"-k 2n"、"-k 2,2n"、"-k 2,4n"的結(jié)果是等價(jià)的,都只對(duì)第2字段按照數(shù)值進(jìn)行排序。但默認(rèn)的排序規(guī)則不會(huì)有這樣的問(wèn)題,因?yàn)槟J(rèn)排序規(guī)則能識(shí)別所有字符,也就是說(shuō)"-k 2,3"、"-k 2"、"-k 2,2"、"-k 2,4"是互不等價(jià)的。
同理,"-d"的字典排序規(guī)則只能識(shí)別字母、數(shù)字和空白字符,所以遇到非這3類(lèi)字符時(shí)也將立即結(jié)束當(dāng)前key的排序。"-h"和"-M"也都有字符的識(shí)別限制,處理方式也一樣。關(guān)于"-h"和"-M"選項(xiàng)的說(shuō)明,見(jiàn)info sort。
需要特意說(shuō)明的是:n同樣不識(shí)別空字符串,發(fā)現(xiàn)空字符串時(shí)也結(jié)束排序。這可能會(huì)適得按數(shù)值排序的結(jié)果出人意料。例如:
[root@linuxidc ~]# echo -e "b 100:200 200 a 110 300" | tr ':' ''|sort -t ' ' -k2n b 100200 200 a 110 300
對(duì)于"b 100200 200"這樣的行,"-k 2n"使得該key為"100200"。雖然結(jié)果看上去是100200,但卻只對(duì)100進(jìn)行排序,也就是說(shuō)它小于110。這就造成了數(shù)值排序的假象,100200竟然比110小。
(5).默認(rèn)情況下,sort會(huì)進(jìn)行一次"最后的排序"。使用"-s"選項(xiàng)將禁止"最后的排序","-u"選項(xiàng)隱含"-s"選項(xiàng)。
考慮這樣一種情況:兩行在所有key的排序結(jié)果上都完全相同,應(yīng)該如何決定這兩行的先后順序?
例如:
[root@linuxidc ~]# echo -e "b 100 200 a 100 300" | sort -t ' ' -k2n a 100 300 b 100 200
第一行為"b 100 200",第二行為"a 100 300"。由于第2字段都是100,所以這兩行在該key上的數(shù)值排序的結(jié)果相同,于是sort采取最后的手段,完全按照默認(rèn)規(guī)則(即按字符集排序規(guī)則升序排序)對(duì)整行進(jìn)行一次排序,這次排序稱(chēng)為"最后的排序"(info sort中稱(chēng)為last-resort comparison)。由于最后的排序過(guò)程中,第一個(gè)字符a<b,所以最終結(jié)果將是第二行"a 100 300"在第一行"b 100 200"的前面。
禁止"最后的排序"后,對(duì)那些排序key相同的行,將保留被讀取時(shí)相對(duì)順序。即,先讀取的排在前面。
如果上面的例子中,第二字段不采用數(shù)值排序,而是默認(rèn)排序規(guī)則排序呢?如下:
[root@linuxidc ~]# echo -e "b 100 200 a 100 300" | sort -t ' ' -k2 b 100 200 a 100 300
由于默認(rèn)的排序規(guī)則是按照字符集排序規(guī)則進(jìn)行排序,它能識(shí)別所有的字符,所以會(huì)對(duì)"-k2"整個(gè)key進(jìn)行排序,該key會(huì)自動(dòng)擴(kuò)展為第2字段和第3字段,由于第三字段的2小于3,所以結(jié)果中第一行排在第二行的前面。即使如此,sort還是進(jìn)行了"最后的排序",只不過(guò)"最后的排序"不影響排序結(jié)果。
如果未指定任何排序選項(xiàng),其本身就是完全默認(rèn)的,因此沒(méi)必要再做最后的排序,所以將不會(huì)進(jìn)行"最后的排序"。如果指定的是"-r"選項(xiàng),由于"-r"是對(duì)最終結(jié)果進(jìn)行反轉(zhuǎn)排序,因此會(huì)影響這次的"最后的排序"的結(jié)果。
(6).sort的使用建議。
搞清楚了以上幾點(diǎn),是否感覺(jué)sort能實(shí)現(xiàn)幾乎所有的排序需求呢?只要文件夠規(guī)則,sort就能控制任何一列或多列的排序方式,并且可以設(shè)置出是否跨列、跨字符、跨key排序。
這里有幾個(gè)sort使用建議,算是最后的補(bǔ)充。
任何時(shí)候想對(duì)單個(gè)字段或單個(gè)字符排序時(shí),都建議寫(xiě)出POS2,且POS2=POS1,這樣能?chē)?yán)格排序key的范圍只為那個(gè)字段或字符。例如,使用"-k2,2"取代"-k2"。
想對(duì)多個(gè)字段或字符排序時(shí),建議使用多個(gè)"-k"選項(xiàng)指定多個(gè)key,并按需求為每個(gè)key分配私有選項(xiàng)。之所以要如此,是防止無(wú)意中忽視了擴(kuò)展到行尾或者范圍。例如,相對(duì)第2列、第3列按數(shù)值排序,應(yīng)該指定"-k2n -k3n",而不應(yīng)該寫(xiě)成"-k2,3n"。
應(yīng)該總是使用"-b"選項(xiàng)去掉前導(dǎo)空白字符面,防止字段分割時(shí)混亂。"-n"隱含了"-b",所以對(duì)數(shù)值排序時(shí),可以省略"-b"。
對(duì)于大文件,建議寫(xiě)出滿(mǎn)足需求的所有排序命令,然后使用"-s"關(guān)閉"最后的排序"。因?yàn)?最后的排序"對(duì)每個(gè)整行進(jìn)行排序,性能非常低。
最后,給出一個(gè)測(cè)試題:假設(shè)一些待排序的日志文件中的內(nèi)容格式如下:
4.150.156.3 - - [01/Apr/2004:06:31:51 +0000] message 1
211.24.3.231 - - [24/Apr/2004:20:17:39 +0000] message 2
能否理解下面兩條等價(jià)的命令?
sort -s -t ' ' -k 4.9n -k 4.5M -k 4.2n -k 4.14,4.21 file*.log | sort -s -t '.' -k 1,1n -k 2,2n -k 3,3n -k 4,4n sort -s -t ' ' -k 4.9n -k 4.5M -k 4.2n -k 4.14,4.21 file*.log | sort -s -t '.' -n -k1 -k2 -k3 -k4
總結(jié)
以上是生活随笔為你收集整理的Linux文件排序工具 sort 命令详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 测孕棒怎么看怀孕(测孕棒多久能测出怀孕)
- 下一篇: 什么是认知障碍(什么是认知)