據(jù)統(tǒng)計(jì))
先給結(jié)論Linux 下的 sort 命令根本不是“把文本行按字母排一下”這么簡(jiǎn)單。它真正解決的是文本行、表格字段、日志記錄、配置列表、文件列表的有序化處理尤其是當(dāng)你需要按數(shù)值大小、按月份、按文件大小、按某個(gè)字段去排序或者在做數(shù)據(jù)去重、求交集差集、檢查重復(fù)項(xiàng)時(shí)sort 配合 uniq、awk、cut 能頂半條管道命令的命。這篇文章適合三類人剛接觸 Linux 系統(tǒng)命令的初學(xué)者、準(zhǔn)備運(yùn)維和開發(fā)面試的求職者、日常要處理日志和數(shù)據(jù)文件的技術(shù)人。最值得關(guān)注的不是 sort 有多少個(gè)參數(shù)而是什么時(shí)候該用哪個(gè)參數(shù)組合以及排序之后的結(jié)果怎么驗(yàn)證才不算白排。下面直接按實(shí)際操作順序拆開講。1. 先用一個(gè)真實(shí)的“混亂文件”理解 sort 的默認(rèn)行為很多人第一次用 sort 是在終端里敲sort file.txt結(jié)果發(fā)現(xiàn)輸出“看起來按字母排了但又好像哪里不對(duì)”。這不是命令有問題而是你沒有理解 sort 的默認(rèn)排序規(guī)則。1.1 默認(rèn)排序不是你想的“按字母順序”sort 命令的默認(rèn)行為是以字典序lexicographical order進(jìn)行排序并且排序的單位是整行文本。所謂字典序就是逐字符比較 ASCII 碼值。這意味著數(shù)字10和2排列時(shí)10會(huì)排在2前面因?yàn)榈谝粋€(gè)字符是1而1的 ASCII 碼比2小??磦€(gè)實(shí)際例子。假設(shè)你有一個(gè)文件scores.txt內(nèi)容是alice 85 bob 100 carol 70 dave 95直接運(yùn)行sort scores.txt輸出是alice 85 bob 100 carol 70 dave 95看起來好像沒問題因?yàn)槊直旧硪呀?jīng)按字母排好了。但如果你把文件內(nèi)容改成alice 85 bob 100 carol 70 dave 95 eric 12再運(yùn)行sort scores.txt會(huì)得到alice 85 bob 100 carol 70 dave 95 eric 12看起來還是有規(guī)律的因?yàn)槊质鬃帜妇褪?a、b、c、d、e。可如果你玩心大一點(diǎn)把名字全部去掉只保留數(shù)字85 100 70 95 12運(yùn)行sort scores.txt結(jié)果會(huì)變成100 12 70 85 95這才是很多人第一次用 sort 時(shí)最困惑的地方為什么 100 排到了最前面因?yàn)?sort 默認(rèn)不認(rèn)數(shù)字大小它只認(rèn)字符。1.2 先明確 sort 的三個(gè)默認(rèn)規(guī)則在使用任何高級(jí)參數(shù)之前先把默認(rèn)規(guī)則記死排序單位是“行”不是“單詞”或“字段”。排序比較基于當(dāng)前 locale 環(huán)境的字符集規(guī)則在多數(shù) Linux 系統(tǒng)里默認(rèn)是Clocale 或en_US.UTF-8。數(shù)字和字母混排時(shí)不要指望它自動(dòng)按“人類直覺”排序。注意在腳本里寫sort file.txt以前先問自己一句話——我是在排文本還是在排數(shù)字如果包含數(shù)字大小邏輯一定要加-n參數(shù)。這個(gè)默認(rèn)行為不是 bug而是 Unix 哲學(xué)的體現(xiàn)sort 不知道你的數(shù)據(jù)是什么類型它只做最樸素的“逐字符比較”。這也是為什么后面有一大堆參數(shù)來修正它。2. 最常被忽略的基礎(chǔ)參數(shù)輸出、輸入、反向很多資料會(huì)把-n、-k當(dāng)作重點(diǎn)反而把最常用的幾個(gè)基礎(chǔ)參數(shù)漏掉。實(shí)際寫命令時(shí)它們出場(chǎng)率極高。2.1 輸出到文件-o 比重定向更可靠你可能會(huì)想排序結(jié)果要保存直接寫sort input.txt output.txt不就行了大多數(shù)時(shí)候是可以的。但如果你寫成sort file.txt file.txt這會(huì)把file.txt原文件內(nèi)容清空因?yàn)?shell 會(huì)先創(chuàng)建并截?cái)嘀囟ㄏ蚰繕?biāo)再執(zhí)行 sort。為避免這種低級(jí)但破壞性極大的錯(cuò)誤sort 提供了-o參數(shù)sort file.txt -o file.txt-o參數(shù)內(nèi)部會(huì)正確處理輸入和輸出為同一文件的情況不需要先輸出到臨時(shí)文件再移動(dòng)。對(duì)于需要在腳本里原地排序的場(chǎng)景-o是更穩(wěn)的選擇。2.2 反向排序-r-r參數(shù)表示 reverse即反向排序??梢院蛿?shù)字、字段、月份等參數(shù)疊加使用。sort -nr scores.txt這個(gè)組合很常見-n按數(shù)字大小-r從大到小。日志分析里統(tǒng)計(jì)訪問量排名基本都會(huì)用到sort -nr。2.3 唯一排序-u-u表示 unique即去除重復(fù)行。注意它和uniq命令的區(qū)別uniq要求重復(fù)行必須相鄰才能去重sort -u會(huì)先排序在排序過程中去重所以即使重復(fù)行散落在文件各處也能去掉。sort -u list.txt如果需要統(tǒng)計(jì)每個(gè)唯一值出現(xiàn)多少次可以配合uniq -csort list.txt | uniq -c注意先sort再uniq否則uniq只會(huì)去掉相鄰重復(fù)統(tǒng)計(jì)會(huì)不準(zhǔn)。3. 按數(shù)字大小排序-n 是你的第一個(gè)拐杖數(shù)字排序是 sort 使用頻率最高的場(chǎng)景也是最容易出錯(cuò)的場(chǎng)景。默認(rèn)按字符排所以必須用-n告訴 sort“把字段內(nèi)容當(dāng)成數(shù)值來比較”。3.1 單列數(shù)字排序回到剛才的scores.txt如果文件內(nèi)容是alice 85 bob 100 carol 70 dave 95 eric 12按第二列數(shù)字從低到高排序sort -k2 -n scores.txt輸出eric 12 carol 70 alice 85 dave 95 bob 1003.2 按數(shù)字反向排序sort -k2 -nr scores.txt輸出bob 100 dave 95 alice 85 carol 70 eric 12每次加-n之前都要確認(rèn)這一列是真的“純數(shù)字”。如果列里有12GB、1.5K這種帶單位的寫法-n就不認(rèn)識(shí)了需要-h參數(shù)。3.3 帶單位的人可讀數(shù)字-h這個(gè)參數(shù)非常實(shí)用。假設(shè)目錄文件大小列表長(zhǎng)這樣2K 1M 300K 1G 512M直接sort -n不對(duì)sort -h才是正解。-h會(huì)解析K、M、G、T等后綴然后比較真實(shí)大小sort -h file.txt處理du -h的輸出時(shí)sort -h幾乎是標(biāo)配。4. 按字段排序-k 是 sort 的核心靈魂默認(rèn) sort 是按整行排。但實(shí)際場(chǎng)景里我們經(jīng)常面對(duì)的是“每一行有多個(gè)字段”的表格型數(shù)據(jù)。這時(shí)候必須用-k指定排序的字段范圍。4.1 字段分隔符-t-t參數(shù)指定字段分隔符。默認(rèn)的分隔符是“空格到空格的過渡”也就是把連續(xù)空格作為一個(gè)分隔符處理。但如果你處理的是 CSV 文件逗號(hào)分隔、passwd 文件冒號(hào)分隔或日志文件可能有多個(gè)空格最好顯式指定。sort -t : -k1 /etc/passwd這條命令按第一個(gè)字段用戶名排序。-t :告訴 sort 用冒號(hào)作為分隔符。用逗號(hào)分隔的 CSV 文件sort -t , -k2 -n data.csv這里有個(gè)很常見的坑如果字段內(nèi)容本身包含逗號(hào)比如Smith, John簡(jiǎn)單的-t ,就不夠用了需要借助cut或awk先處理或者使用更復(fù)雜的-k定義。sort 本身不理解 CSV 的引號(hào)邏輯。4.2 -k 的數(shù)字含義起點(diǎn)和終點(diǎn)-k的完整格式是-k 起始字段, 結(jié)束字段比如-k2從第 2 個(gè)字段到行尾作為排序鍵。-k2,2只以第 2 個(gè)字段作為排序鍵不包含后面字段。-k2,3以第 2 到第 3 個(gè)字段作為排序鍵。區(qū)別很大??匆粋€(gè)例子文件內(nèi)容是alice 85 90 bob 100 80 carol 70 95執(zhí)行sort -k2 -n排序鍵是“第2列以后的所有內(nèi)容”即85 90、100 80、70 95這三個(gè)整體。因?yàn)榈谌胁煌瑫?huì)影響排序結(jié)果。執(zhí)行sort -k2,2 -n則是只看第2列第三列不參與比較。4.3 混合多列排序如果要先按第 1 列排再按第 2 列排可以寫多個(gè)-ksort -k1,1 -k2,2n data.txt這條命令先按第 1 列字典序排如果第 1 列相同再按第 2 列數(shù)字升序排。-k2,2n中的n是緊跟字段編號(hào)的修飾符。這種多級(jí)排序在處理報(bào)表、人員名單、成績(jī)單時(shí)非常常用。比如體育比賽排名先比積分積分相同再比凈勝球就可以用多個(gè)-k實(shí)現(xiàn)。4.4 不穩(wěn)定的排序結(jié)果需要 -s 穩(wěn)定排序sort 默認(rèn)不是穩(wěn)定排序。意思是如果兩行的排序鍵完全相同它們?cè)械南鄬?duì)順序可能會(huì)被打亂。這在某些場(chǎng)景下會(huì)觸發(fā)問題比如你已經(jīng)按日期排好序再按部門排序時(shí)希望同部門內(nèi)部仍保留日期的先后順序。這時(shí)要加-ssort -s -k2,2 data.txt-s表示 stable穩(wěn)定排序。對(duì)于多級(jí)排序的場(chǎng)景-s能避免“第二次排序破壞第一次排序結(jié)果”的問題。我在處理需要分組的日志數(shù)據(jù)時(shí)幾乎必加-s。5. 現(xiàn)場(chǎng)實(shí)測(cè)用一份員工表把參數(shù)組合跑一遍為了把上面的參數(shù)串起來用一個(gè)虛構(gòu)但典型的員工數(shù)據(jù)文件employees.txtAlice,Engineering,8500,2021 Bob,Sales,9200,2019 Carol,Engineering,9200,2020 Dave,Sales,7800,2022 Eve,Engineering,8500,2021 Frank,HR,8100,2020需求是按薪資第三列從高到低排薪資相同則按入職年份第四列從早到晚排。命令sort -t , -k3,3nr -k4,4n employees.txt這里-t ,逗號(hào)分隔。-k3,3nr第三列數(shù)字排序反向。-k4,4n第四列數(shù)字排序升序。輸出Bob,Sales,9200,2019 Carol,Engineering,9200,2020 Alice,Engineering,8500,2021 Eve,Engineering,8500,2021 Frank,HR,8100,2020 Dave,Sales,7800,2022注意 Alice 和 Eve 的薪資、年份都相同她倆之間的順序在 sort 里是不保證穩(wěn)定的。如果希望它們保持原文件中的先后順序加-s即可sort -s -t , -k3,3nr -k4,4n employees.txt5.1 比較時(shí)容易忽略的關(guān)鍵點(diǎn)實(shí)際寫命令時(shí)會(huì)發(fā)現(xiàn)-k3,3nr和-k3nr看起來像但結(jié)果可能不一樣。因?yàn)?k3會(huì)讓第三個(gè)字段之后的逗號(hào)和字符也參與比較。如果第三列數(shù)值相同第四列的內(nèi)容就會(huì)變成次級(jí)比較項(xiàng)影響排序結(jié)果。所以指定明確的范圍-k3,3是更穩(wěn)妥的寫法。表格對(duì)比一下寫法含義適用場(chǎng)景-k3從第3列到行尾作為排序鍵第3列之后無其他列或希望后續(xù)列參與比較-k3,3僅第3列作為排序鍵只希望按第3列排序后續(xù)列不參與-k3,4第3到第4列作為排序鍵組合多列作為一個(gè)排序鍵如果業(yè)務(wù)邏輯是“按薪資排薪資相同再按年份排”必須寫成-k3,3 ... -k4,4而不是-k3 ... -k4。5.2 字段里的前導(dǎo)空格問題用-t指定分隔符后字段內(nèi)容可能帶有前導(dǎo)空格。比如Alice, Engineering, 8500此時(shí)第二列是Engineering前面有空格第三列是8500前面有空格。sort 會(huì)把這些空格當(dāng)成字段內(nèi)容的一部分導(dǎo)致排序結(jié)果不符合預(yù)期。處理辦法數(shù)據(jù)預(yù)處理用 sed、awk 去掉多余空格。指定分隔符時(shí)把空格也納入考慮例如-t , 逗號(hào)加空格但這樣對(duì)不規(guī)律空格不適用。用cut或awk先將字段裁剪干凈再交給 sort。我個(gè)人比較推薦先用 awk 清理再接 sort而不是在 sort 參數(shù)里硬扛awk -F , {gsub(/^ | $/, , $2); print $1,$2,$3} data.txt | sort -t , -k2,26. 進(jìn)階場(chǎng)景日志、去重、交集、隨機(jī)排序sort 不只是給人看文件排個(gè)序它在管道處理和數(shù)據(jù)清洗中承擔(dān)著更重的角色。6.1 日志按時(shí)間字段排序假設(shè) Nginx 或 Apache 訪問日志中每一行的開頭是時(shí)間戳2025-01-10 10:23:01 192.168.1.2 /index.html 2025-01-09 22:11:45 192.168.1.3 /about.html 2025-01-10 08:05:22 192.168.1.4 /contact.html按時(shí)間從前到后排序sort -k1,1 -k2,2 log.txt這里第一列是日期第二列是時(shí)間都是字典序可比的YYYY-MM-DD 和 HH:MM:SS 的字典序即時(shí)間順序所以不需要-n。6.2 配合 uniq 做統(tǒng)計(jì)和去重最常見的組合是sort access.log | awk {print $1} | sort | uniq -c這條命令的作用是從訪問日志中提取 IP 地址統(tǒng)計(jì)每個(gè) IP 出現(xiàn)的次數(shù)。注意這里用了兩次 sort第一次是把日志按 IP 排好讓相同 IP 相鄰第二次 sort 其實(shí)是針對(duì)uniq -c的輸出按次數(shù)排序如果需要在前面加-n才能按次數(shù)數(shù)字排。更完整的按訪問次數(shù)從高到低派sort access.log | awk {print $1} | sort | uniq -c | sort -nr第3段sort默認(rèn)按 IP 字典序排uniq -c已經(jīng)統(tǒng)計(jì)了次數(shù)最后一層sort -nr才讓次數(shù)從大到小排。整個(gè)過程是先“分組計(jì)數(shù)”再“排序展示”。6.3 兩個(gè)文件求交集和差集comm 依賴 sortcomm命令比較兩個(gè)已排序文件。如果不先 sort結(jié)果會(huì)亂。求交集sort a.txt -o a_sorted.txt sort b.txt -o b_sorted.txt comm -12 a_sorted.txt b_sorted.txt求差集只在 a 中出現(xiàn)comm -23 a_sorted.txt b_sorted.txt這種用法在比對(duì)配置文件差異、檢查黑名單名單列表時(shí)很實(shí)用。6.4 隨機(jī)排序-R-R參數(shù)按隨機(jī)哈希排序不是真正的完全隨機(jī)但用于抽樣、打亂順序基本夠sort -R list.txt | head -20如果要做可復(fù)現(xiàn)的隨機(jī)抽樣可以先設(shè)置環(huán)境變量LC_ALLC再執(zhí)行因?yàn)椴煌?locale 的隨機(jī)行為可能不同。6.5 忽略大小寫排序-f默認(rèn) sort 區(qū)分大小寫大寫字母會(huì)排在小寫字母之前。如果希望忽略大小寫sort -f words.txt比如Banana和apple默認(rèn)排序時(shí)BASCII 66在aASCII 97前面加了-f后apple在前。6.6 按月份名排序-M-M能識(shí)別英文月份縮寫或全稱并按月份順序排列Jan, Feb, Mar, ...示例sort -M months.txt如果你的系統(tǒng) locale 是中文月份識(shí)別可能不生效需要臨時(shí)切換 localeLC_ALLC sort -M months.txt7. 在 Shell 腳本中安全使用 sort 的細(xì)節(jié)把 sort 寫進(jìn)腳本時(shí)有幾個(gè)小問題容易被忽視一旦出問題排查成本不低。7.1 中文字符排序不要依賴默認(rèn) locale默認(rèn) LC_ALL 可能是en_US.UTF-8或C中文字符的排序結(jié)果會(huì)不同。比如printf 張三\n李四\n王五\n | sort在Clocale 下排序依據(jù)是字節(jié)順序在zh_CN.UTF-8下可能會(huì)按拼音排序也可能按筆畫取決于系統(tǒng)實(shí)現(xiàn)。如果需要穩(wěn)定可預(yù)測(cè)的結(jié)果顯式指定 localeLC_ALLC sort names.txt7.2 臨時(shí)文件目錄大文件排序要關(guān)注 /tmp 空間sort 處理大文件時(shí)如果文件超過內(nèi)存容量會(huì)使用臨時(shí)文件。默認(rèn)臨時(shí)目錄是/tmp。當(dāng)/tmp空間不足時(shí)sort 會(huì)報(bào)錯(cuò)或變慢??梢栽谀_本里顯式指定sort -T /data/tmp largefile.txt-T后面跟臨時(shí)目錄盡量選有足夠空間的掛載點(diǎn)。7.3 管道中的緩沖問題sort 是阻塞命令sort 必須等全部輸入讀完才能開始輸出因?yàn)橐w排序。如果你在管道里用tail -f實(shí)時(shí)日志接 sort會(huì)得不到預(yù)期效果。sort 不適合流式處理。如果要實(shí)時(shí)流式排序需要另想方案sort 本身做不到。7.4 文本編碼問題如果文件是 GBK 編碼sort 用 UTF-8 locale 排序時(shí)會(huì)亂。先轉(zhuǎn)換編碼iconv -f GBK -t UTF-8 file.txt | sort或者臨時(shí)設(shè)置 localeLC_ALLzh_CN.GB18030 sort file.txt具體用哪種取決于系統(tǒng)是否安裝了對(duì)應(yīng) locale。8. 常見報(bào)錯(cuò)和排查思路sort 命令并不復(fù)雜但報(bào)錯(cuò)時(shí)如果只會(huì)看“命令行不對(duì)”很容易繞彎路。我一般按這個(gè)順序排查。8.1 現(xiàn)象排序結(jié)果和預(yù)期完全反了第一步看方向是不是需要-r沒加或者加了但不該加。 第二步看類型是不是該用-n卻忘了加數(shù)字被當(dāng)成字符串排了。 第三步看 locale不同 locale 下同一份數(shù)據(jù)的排序結(jié)果可能不一致。8.2 現(xiàn)象字段排序沒生效先確認(rèn)分隔符。如果文件是逗號(hào)分隔卻用了默認(rèn)空格分隔-k2根本定位不到正確字段。驗(yàn)證方式很簡(jiǎn)單awk -F , {print $2} data.txt | head看看第二字段是不是想要的。然后再跑 sort。8.3 現(xiàn)象排序后重復(fù)行沒去干凈uniq -c的結(jié)果看起來重復(fù)還是很多通常是因?yàn)榕判虿粡氐紫嗤?xiàng)沒有完全相鄰。跑一遍sort file.txt | sort -u再去重再查。8.4 現(xiàn)象命令突然變慢大文件排序時(shí)可能是-T指向的目錄空間不足導(dǎo)致多次讀寫臨時(shí)文件。也可能是-k的字段范圍過長(zhǎng)讓 sort 比較成本變高。還有一種情況文件有大量長(zhǎng)行排序時(shí)內(nèi)存占用高。建議先wc -l看行數(shù)du -h看文件大小再?zèng)Q定是否需要調(diào)-T。8.5 現(xiàn)象CSV 文件排序總是亂CSV 文件如果某個(gè)字段包含逗號(hào)或換行sort 的簡(jiǎn)單字段分割不夠可靠。這種場(chǎng)景下建議先用 Python 的csv模塊預(yù)處理或者用 awk 增強(qiáng)邏輯。sort 只能處理“結(jié)構(gòu)規(guī)整的文本字段”沒有完整 CSV 語義解析能力。9. 面試和實(shí)際工作中最值得記住的 sort 要點(diǎn)很多 Linux 面試題會(huì)問 sort 和 uniq 的組合、sort 默認(rèn)按字符排、-k的區(qū)間定義。這些確實(shí)是高頻考點(diǎn)但實(shí)際工作里更重要的是“組合使用能力”。9.1 高頻命令組合# 統(tǒng)計(jì)文件各行出現(xiàn)次數(shù)降序 sort file.txt | uniq -c | sort -nr # 按第二列數(shù)字升序然后按第一列字母降序 sort -k2,2n -k1,1r data.txt # 按冒號(hào)分隔取第一列去重 sort -t : -k1,1 -u /etc/passwd # 按文件大小排序du 輸出 du -sh * | sort -h # 按數(shù)字比較但忽略大小寫 sort -f -n data.txt9.2 判斷標(biāo)準(zhǔn)什么時(shí)候算“用對(duì)了”單次排序結(jié)果符合業(yè)務(wù)邏輯不只是一個(gè)技術(shù)排序。相同輸入、相同命令輸出結(jié)果可復(fù)現(xiàn)。在管道里前后命令的字段假設(shè)一致。大文件排序時(shí)內(nèi)存和磁盤空間可接受不會(huì) OOM。多級(jí)排序的順序和業(yè)務(wù)優(yōu)先級(jí)一致。9.3 學(xué)習(xí)建議用一個(gè)小數(shù)據(jù)集當(dāng)“練功場(chǎng)”與其背參數(shù)表不如準(zhǔn)備一個(gè) 10 行左右的混合文本文件包含數(shù)字、字母、符號(hào)、多列數(shù)據(jù)然后把以下參數(shù)逐一試一遍-n、-r、-k、-t、-u、-f、-h、-s、-M、-R。觀察每次輸出尤其注意加-k2,2和-k2的區(qū)別。這個(gè)實(shí)驗(yàn) 10 分鐘就能做完但對(duì)理解 sort 的行為邏輯幫助很大。10. 國(guó)產(chǎn)系統(tǒng)與生產(chǎn)環(huán)境中的注意點(diǎn)最近很多人在問答平臺(tái)搜“麒麟系統(tǒng)命令”“銀河麒麟操作系統(tǒng)命令大全”說明國(guó)產(chǎn) Linux 系統(tǒng)在運(yùn)維生產(chǎn)環(huán)境里越來越常見。在這些系統(tǒng)上使用 sort基本語法沒有區(qū)別但有幾點(diǎn)建議特別留意。10.1 locale 差異更明顯國(guó)產(chǎn)系統(tǒng)可能默認(rèn)使用zh_CN.UTF-8或zh_CN.GB18030sort 的默認(rèn)排序行為會(huì)受影響。同一個(gè)sort -f命令在英文系統(tǒng)和中文本地化系統(tǒng)上處理中英文混合內(nèi)容時(shí)輸出順序可能不同。所以腳本里最好顯式指定export LC_ALLC或按業(yè)務(wù)需求設(shè)置zh_CN.UTF-8。不要在腳本里用“默認(rèn) locale 的偶然行為”來依賴結(jié)果。10.2 舊版本參數(shù)支持差異大量國(guó)產(chǎn)系統(tǒng)基于較老的內(nèi)核和工具鏈sort 的版本可能不是最新的。比如-h參數(shù)在某些精簡(jiǎn)版 coreutils 里可能不可用。驗(yàn)證方式sort --help | grep \-h如果-h不支持可以用du -B1輸出純數(shù)字字節(jié)數(shù)再配合-n排序最后用numfmt --toiec轉(zhuǎn)回人類可讀格式。10.3 腳本兼容性在開發(fā)機(jī)上用 GNU sort 寫得好的腳本移植到其他 Unix 或國(guó)產(chǎn)系統(tǒng)時(shí)多測(cè)一遍按字段排序的結(jié)果。GNU 擴(kuò)展參數(shù)如-h、-R在 POSIX 標(biāo)準(zhǔn)里不一定都有要提前在目標(biāo)環(huán)境驗(yàn)證。11. 幾個(gè)容易讓人忽視的“小坑”和實(shí)戰(zhàn)避坑經(jīng)驗(yàn)整理幾個(gè)我實(shí)際踩過的坑供你參考。11.1 sort -u 不是 uniq 的完全替代sort -u去重時(shí)如果兩行只有部分字段相同它不會(huì)去重因?yàn)樗前凑斜容^。如果要去掉“第一字段相同的行”需要配合-ksort -t , -k1,1 -u data.csv這個(gè)寫法是“按第一字段去重”保留哪一行取決于排序后的第一條。想控制保留哪一行可以先把需要保留的行排到前面。11.2 數(shù)值里的正負(fù)號(hào)、小數(shù)點(diǎn)sort -n對(duì)于負(fù)數(shù)、小數(shù)、科學(xué)計(jì)數(shù)法的支持取決于 locale。標(biāo)準(zhǔn)場(chǎng)景下printf 1.5\n-2\n10\n | sort -n輸出-2 1.5 10如果你的數(shù)據(jù)是1,5這種逗號(hào)小數(shù)格式-n不會(huì)正確處理因?yàn)?locale 里逗號(hào)可能是千分位??梢韵劝讯禾?hào)換成點(diǎn)或者設(shè)置 locale。11.3 不要用 sort 處理超大文件時(shí)裸跑比如一個(gè) 50GB 的日志文件直接sort可能把內(nèi)存和臨時(shí)目錄打滿。更穩(wěn)妥的做法是split -l 1000000 huge_log.txt chunk_ for f in chunk_*; do sort -T /data/tmp $f -o $f.sorted; done sort -m -T /data/tmp chunk_*.sorted -o final_sorted.txt rm -f chunk_*sort -m用于合并多個(gè)已排序文件內(nèi)存占用更可控。這個(gè)流程叫作“外排序”的簡(jiǎn)單手工版。11.4 避免死記參數(shù)用 --help 和 man 判斷每次記不準(zhǔn)參數(shù)時(shí)與其搜網(wǎng)上的答案不如先跑man sort sort --help | less這兩個(gè)命令能覆蓋 90% 的問題。關(guān)鍵是學(xué)會(huì)看“字段范圍修飾符”n、r、f等和“全局修飾符”-n、-r等的區(qū)別。11.5 中文排序不要盲目加 -f-f只忽略 ASCII 字母大小寫對(duì)中文沒有意義。如果需要按拼音排序需要借助iconv把中文轉(zhuǎn)成拼音或拼音首字母再做排序。這種場(chǎng)景下perl 的Unicode::Collate模塊更合適sort 本身不是專門的中文排序工具。12. 在管道里和 awk、cut、sed 配合的完整案例只盯著 sort 一個(gè)命令是不夠的。實(shí)際數(shù)據(jù)處理流程里sort 經(jīng)常只是管道中的一個(gè)環(huán)節(jié)。下面是一個(gè)比較典型的日志統(tǒng)計(jì)任務(wù)。任務(wù)從一段訪問日志中統(tǒng)計(jì)每個(gè) URL 的訪問次數(shù)并按次數(shù)從高到低輸出前 10 個(gè) URL。假設(shè)日志每行格式192.168.1.10 - - [10/Jan/2025:08:12:33 0800] GET /index.html HTTP/1.1 200 1024 192.168.1.11 - - [10/Jan/2025:08:12:35 0800] GET /about.html HTTP/1.1 200 2048用 awk 提取 URL統(tǒng)計(jì)并排序awk {for(i1;iNF;i) if($i ~ /^\/.*HTTP/) {print $i; break}} access.log \ | sed s/HTTP\/1\.[01]// \ | sort \ | uniq -c \ | sort -nr \ | head -10逐段解釋awk找到以/開頭并包含 HTTP 的字段這通常是 URL 字段。sed去掉HTTP/1.1或HTTP/1.0后綴。sort把相同 URL 的行排到一起。uniq -c統(tǒng)計(jì)次數(shù)。sort -nr按次數(shù)降序。head -10取前 10。從這個(gè)流程可以看到sort 的位置很關(guān)鍵它在 uniq 之前負(fù)責(zé)“讓重復(fù)項(xiàng)相鄰”否則 uniq 統(tǒng)計(jì)不對(duì)。它在 uniq 之后負(fù)責(zé)“按次數(shù)排序”這是第二次排序。如果不理解 sort 的兩階段用途只記sort | uniq -c | sort -nr遇到數(shù)據(jù)格式變化時(shí)容易改錯(cuò)。13. 綜合建議怎么練成“拿文本就能排序”的直覺最后說一點(diǎn)學(xué)習(xí)方法上的建議。很多初學(xué)者容易陷入“先把所有參數(shù)背下來”的狀態(tài)但 sort 真正難的不是參數(shù)記憶而是“定位排序字段”和“判斷排序語義”。拿到一份新數(shù)據(jù)先問三個(gè)問題每一行的分隔符是什么空格、逗號(hào)、冒號(hào)還是固定寬度要按第幾個(gè)字段排這個(gè)字段是字符串、整數(shù)、浮點(diǎn)數(shù)還是帶單位的文本多個(gè)字段同時(shí)排序時(shí)優(yōu)先級(jí)是什么回答完這三個(gè)問題90% 的 sort 命令已經(jīng)能寫出來。剩下的參數(shù)只是在表達(dá)你的判斷。建議在終端里準(zhǔn)備一個(gè)sample.txt放進(jìn)各種亂七八糟的行然后隨手敲命令驗(yàn)證。別怕輸錯(cuò)輸錯(cuò)一次多觀察一次比讀十篇教程都管用。另外如果你在用國(guó)產(chǎn)服務(wù)器或者專門面向信創(chuàng)場(chǎng)景的系統(tǒng)記得把 locale 和 coreutils 版本納入檢查范圍。同樣的 sort 命令在標(biāo)準(zhǔn) Linux 上正常在精簡(jiǎn)環(huán)境里可能表現(xiàn)不同。能用sort --version看到版本信息再?zèng)Q定放心使用還是換一種實(shí)現(xiàn)。sort 的最終價(jià)值從來不是“排個(gè)序”這么簡(jiǎn)單。它讓文本數(shù)據(jù)變得可比較、可統(tǒng)計(jì)、可檢索、可合并。理解這一點(diǎn)你就不會(huì)只在“按字母排序”的層面使用它了。