Linux sort命令详解:从文本排序到日志分析实战
1. 为什么每个 Linux 使用者都应该掌握 sort在日常使用 Linux 的过程中我们经常需要面对各种文本处理任务。比如查看日志时想按照时间排序、分析数据时想找出数值最大的几行、处理配置文件时想去掉重复项……如果每次都靠人工一个个看效率极低。而sort命令就是 Linux 系统内置的一个专门用来做排序处理的利器。1.1 sort 命令是什么sort是 Linux 系统中最常用的文本处理命令之一它能够将输入文件中的每一行作为一条记录按照指定的规则进行排序然后把排序后的结果输出到标准输出设备通常是终端或者指定的文件中。它和grep、awk、sed一起被很多运维工程师称为 Linux 文本处理的“四剑客”。其中grep负责过滤和匹配文本。sed负责对文本进行流式编辑、替换。awk负责格式化处理和报表输出。sort负责排序归类是数据整理的第一道工序。1.2 sort 命令解决什么问题很多场景下我们拿到的原始数据是杂乱无章的。sort命令解决的问题非常直接让数据按照字典顺序、数值大小或者日期先后排列便于人眼阅读。配合uniq命令统计并去除重复数据。在编写 Shell 脚本时对数据进行预处理为后续的awk、cut分析做准备。对日志文件、配置文件、数据表文件进行排序方便对比不同版本之间的差异。1.3 常见应用场景从实际开发和运维的角度来看sort的典型场景包括服务器进程列表按内存或 CPU 占用排序比如把ps命令的输出交给sort处理。日志分析时把接口访问耗时从高到低排列找出最耗时的接口。统计文件中每个单词出现的次数sort和uniq组合使用是最经典的做法。对用户列表、IP 列表、域名列表去重排序生成干净的清单。在 CI/CD 脚本里对构建产物清单做排序校验。可以这样说只要 Linux 上有文本数据需要整理sort几乎总是第一个被想到的命令。它虽然简单却是日常运维和开发中不可或缺的基础能力。2. 环境准备与基础概念在进行正式操作之前先确认一下运行环境。本文的示例均在常见的 Linux 发行版下运行无论你是使用 Ubuntu、CentOS、Debian还是国产的麒麟操作系统、统信 UOSsort命令都是系统自带的不需要额外安装。2.1 查看版本与环境在终端中输入以下命令可以查看当前系统使用的sort版本sort --version输出结果大致如下sort (GNU coreutils) 8.32 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3: GNU GPL version 3 or later https://gnu.org/licenses/gpl.html. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Mike Haertel and Paul Eggert.需要注意的是不同发行版自带的 coreutils 版本会有差异导致某些选项的行为细节略有不同。但本文要讲的核心选项在所有主流 Linux 系统上都能正常使用所以版本差异不影响你跟着操作。2.2 准备一份练习数据为了后面演示方便我先创建一份示例数据文件。打开终端执行下面的命令mkdir -p ~/sort-demo cd ~/sort-demo cat fruits.txt EOF banana Apple cherry apple Banana date elderberry EOF这里创建了一个名为fruits.txt的文件里面有几行水果名称故意混合了大小写方便后面演示排序规则。再创建一个数值型的数据文件cat scores.txt EOF 90 88 100 75 102 23 45 EOF这份数据里有 100 和 102 这种多位数用来演示默认字典排序和数值排序的区别再合适不过。3. sort 命令核心语法与常用选项拆解3.1 基础语法sort命令的基本语法如下sort [选项] [文件...]如果不指定文件或者文件名为-sort会从标准输入读取数据。这也意味着sort经常配合管道符使用。最简单的写法sort fruits.txt这条命令会按照每行字符的字典顺序把fruits.txt内容输出到屏幕但不会修改原文件。输出结果默认是Apple Banana apple banana cherry date elderberry注意这里有两个细节大写字母排在前面小写字母排在后面。因为默认排序规则按照 ASCII 码比较大写 A65小于小写 a97。原文件没有被修改。sort默认只输出结果不改变源文件。3.2 最常用的选项-n、-r、-k、-t、-u我把sort的高频选项整理成了下表建议收藏备用选项完整写法作用-n--numeric-sort按照数值大小排序-r--reverse逆向排序从大到小-k--keyKEYDEF指定排序的字段列-t--field-separatorSEP指定字段分隔符-u--unique去重并排序只保留一行-f--ignore-case忽略大小写-b--ignore-leading-blanks忽略每行开头的空白字符-o--outputFILE把结果输出到指定文件-c--check检查文件是否已经排序-m--merge合并多个已排序文件-h--human-numeric-sort按照人类可读的数字排序支持 K、M、G 等单位-R--random-sort随机排序-s--stable稳定排序启用最后一次比较作为排序依据下面重点讲几个最容易踩坑的选项。3.3 字典排序和数值排序的区别这是初学者最容易搞混的地方。默认情况下sort是按照字典顺序也就是字符顺序排序的。现在对上文的scores.txt执行默认排序sort scores.txt输出100 102 23 45 75 88 90可以看到100排在了23前面。因为字典排序是逐位比较字符的1的 ASCII 码是 492的 ASCII 码是 504的是 52所以以1开头的数总是排在前面。这显然不是我们期望的数值排序。加上-n选项后sort -n scores.txt输出23 45 75 88 90 100 102这才是真正的按数值大小排序。所以排序对象是数值时一定要记得加-n。3.4 反向排序-r选项用于从大到小排列。比如查看哪个分数最高sort -n -r scores.txt输出102 100 90 88 75 45 23在真实场景中sort -nr经常会跟其他命令搭配。比如查看当前目录下文件大小的排行ls -l | sort -nr -k5这条命令先列出文件详情然后按照第五列文件大小数值从大到小排序。后面会详细讲-k。3.5 去重排序-u选项可以在排序过程中去除重复行。和单独使用uniq不同sort -u是全局去重不需要像uniq那样要求重复行必须相邻。先准备一份有重复数据的文件cat ips.txt EOF 192.168.1.10 192.168.1.2 192.168.1.10 192.168.1.3 192.168.1.2 10.0.0.1 EOF执行sort -u ips.txt输出10.0.0.1 192.168.1.10 192.168.1.2 192.168.1.3这里去掉了重复的两行 IP。如果你先跑sort ips.txt再用uniq效果也是一样的但sort -u一条命令更简洁。3.6 忽略大小写排序默认排序规则区分大小写想让大小写不敏感的排序可以用-f选项sort -f fruits.txt输出Apple apple Banana banana cherry date elderberry可以看到大小写被合并处理了Apple 和 apple 被当成同一个单词参与排序。这个选项在排序日志中的人名、URL、文件名时非常有用。3.7 指定排序字段-k 和 -tsort最强大的地方在于它可以按照指定的列进行排序而不只是整行比较。这需要配合两个选项-t指定分隔符告诉sort每行数据用什么字符来分成多个字段。-k指定按第几个字段排序。举个例子假设有一个员工信息文件每行包含姓名、部门和薪资用冒号分隔cat employees.txt EOF Alice:Engineering:9500 Bob:Sales:8700 Cindy:Engineering:12000 David:Sales:6500 Eva:HR:7800 Frank:HR:9200 EOF现在想按薪资从高到低排列可以这样写sort -t : -k 3 -nr employees.txt解释一下这条命令-t :表示字段分隔符是冒号。-k 3表示使用第三个字段也就是薪资列作为排序依据。-nr表示数值排序并且反向排列。输出Cindy:Engineering:12000 Alice:Engineering:9500 Frank:HR:9200 Bob:Sales:8700 David:Sales:6500 Eva:HR:7800如果想先按部门排序同部门内再按薪资排序可以写sort -t : -k 2 -k 3 -n employees.txt这里连续写了两个-k说明第一排序关键字是部门第二排序关键字是薪资。结果如下Alice:Engineering:9500 Cindy:Engineering:12000 Eva:HR:7800 Frank:HR:9200 Bob:Sales:8700 David:Sales:6500-k的完整语法比看起来更灵活比如-k 2,2表示从第二列开始比较到第二列结束也就是只取第二列作为排序键。后面的,和第二个数字用来限定区间的起始和结束位置。如果只写-k 2则表示从第二列开始一直到行尾都作为排序键。在处理复杂文本时这个细节会直接影响排序结果。3.8 按人类可读数字排序-h在查看磁盘占用、文件大小时输出来往往是这种格式2.1G 350M 890K 1.2G如果直接sort -n由于带单位字符结果会不正确。这时应该使用-hcat sizes.txt EOF 2.1G 350M 890K 1.2G EOF sort -h sizes.txt输出890K 350M 1.2G 2.1G可以看到-h能正确理解 K、M、G 等单位按实际大小排序。这非常适用于du -h或ls -lh输出的场景du -h --max-depth1 /var | sort -hr这条命令会找出/var目录下占用空间最大的子目录是排查磁盘占用问题的高频组合。3.9 输出到文件-osort默认把结果输出到屏幕如果想保存结果到文件很多人会想到重定向sort -n scores.txt sorted_scores.txt这样写没问题。但有一个特殊场景需要注意如果你想覆盖原文件比如执行sort -n scores.txt scores.txt这是一个危险操作。因为 shell 会先打开并清空scores.txt然后sort再去读取时文件已经变成空文件了。安全的做法是使用-o选项sort -n scores.txt -o scores.txtsort内部会先完成所有排序再写入文件所以不会丢失数据。日常处理配置文件、临时文件时建议养成使用-o的习惯。3.10 检查是否已排序-c在处理大规模数据时有时候需要判断一个文件是否已经排好序这时可以用-csort -c scores.txt如果文件已经排序命令会静默退出退出码为 0。如果没排序会输出类似sort: scores.txt:3: disorder: 75并且退出码为 1。这个选项在编写脚本校验数据时很有用。带-n检查数值排序也是常见写法sort -n -c scores.txt3.11 合并已排序文件-m如果手上有多个已经排好序的文件想把它们合并成一个有序文件用sort -m比直接sort效率更高因为它不需要重新对所有数据排序只需要归并。cat a.txt EOF apple banana EOF cat b.txt EOF cherry date EOF sort -m a.txt b.txt输出apple banana cherry date注意-m要求输入文件本身已经有序否则结果不正确。3.12 随机排序-R-R选项会打乱数据顺序产生随机排序结果。比如随机抽取列表、随机分配任务时可以使用sort -R ips.txt由于每次执行结果都不相同如果你需要一个可复现的随机顺序可以加上--random-source指定随机源文件不展开讨论知道这个选项即可。4. 综合实战使用 sort 完成日志分析与数据统计接下来我们把已经学过的选项组合起来完成一个常见的实战任务分析服务器访问日志中的 IP 访问次数找出访问次数最多的前 5 个 IP。4.1 准备一份模拟日志为了方便演示先创建一份 Nginx 风格的访问日志片段cat access.log EOF 192.168.1.10 - - [10/Oct/2024:10:10:10 0800] GET /index.html HTTP/1.1 200 1234 192.168.1.2 - - [10/Oct/2024:10:10:11 0800] GET /api/user HTTP/1.1 200 256 192.168.1.10 - - [10/Oct/2024:10:10:12 0800] GET /favicon.ico HTTP/1.1 404 55 10.0.0.1 - - [10/Oct/2024:10:10:13 0800] GET /index.html HTTP/1.1 200 1234 192.168.1.3 - - [10/Oct/2024:10:10:14 0800] POST /api/login HTTP/1.1 302 0 192.168.1.10 - - [10/Oct/2024:10:10:15 0800] GET /api/user HTTP/1.1 200 256 192.168.1.2 - - [10/Oct/2024:10:10:16 0800] GET /index.html HTTP/1.1 200 1234 10.0.0.1 - - [10/Oct/2024:10:10:17 0800] GET /api/login HTTP/1.1 200 128 192.168.1.3 - - [10/Oct/2024:10:10:18 0800] GET /index.html HTTP/1.1 200 1234 192.168.1.10 - - [10/Oct/2024:10:10:19 0800] GET /index.html HTTP/1.1 200 1234 EOF日志中每一行的第一个字段就是访问者的 IP 地址。4.2 第一步提取 IP 列表使用awk或cut提取第一列awk {print $1} access.log输出192.168.1.10 192.168.1.2 192.168.1.10 10.0.0.1 192.168.1.3 192.168.1.10 192.168.1.2 10.0.0.1 192.168.1.3 192.168.1.104.3 第二步排序把提取出来的 IP 交给sort让相同的 IP 聚集在一起awk {print $1} access.log | sort排序后的结果相同 IP 就会相邻排列。这一步是整个统计流程中必不可少的前置操作因为后面要用的uniq -c只能统计相邻的重复行。4.4 第三步统计次数uniq -c会统计每行重复出现的次数awk {print $1} access.log | sort | uniq -c输出3 10.0.0.1 4 192.168.1.10 2 192.168.1.2 2 192.168.1.3此时每行的第一列是出现次数第二列是 IP 地址。4.5 第四步按次数排序uniq -c输出的次数带有前导空格需要忽略空格并按数值排序最后取前 5awk {print $1} access.log | sort | uniq -c | sort -nr | head -5分析一下这里为什么用sort -nr-n让uniq -c输出的计数按照数值而非字典顺序排序。-r从高到低排列。head -5只显示前 5 行即可。输出4 192.168.1.10 3 10.0.0.1 2 192.168.1.2 2 192.168.1.3这样我们就成功找出了访问量最高的 IP。这个命令组合是运维排查、安全分析里的经典流水线请务必记住。4.6 扩展统计接口访问耗时 Top N假设有一个接口耗时日志每一行的格式是接口名 耗时(毫秒)cat latency.log EOF /api/user 123 /api/login 34 /api/user 456 /api/index 89 /api/search 234 /api/upload 1200 /api/user 78 /api/login 567 EOF要找出耗时最高的接口和耗时sort -k 2 -nr latency.log | head -3输出/api/upload 1200 /api/login 567 /api/user 456-k 2是让 sort 只针对第二列进行排序而-nr负责以数值方式降序排列。这一条命令就能快速定位性能瓶颈非常实用。4.7 实战小结通过上面的示例可以看到sort在 Shell 数据处理中扮演的承上启下角色。单独用sort可能效果有限但一旦和awk、uniq、head、tail等命令组合成管道就能完成非常复杂的数据分析任务。5. 常见问题与排查思路在实际使用过程中大家经常会在sort上遇到一些容易迷惑的问题。下面整理了几个高频问题并结合排查思路进行分析。5.1 常见问题对照表问题现象常见原因解决思路数字排序不对100 排在 23 前面没有使用-n选项默认按字典进行字符排序数值排序时加-n去重没生效uniq只处理相邻重复行数据未排序就执行了uniq先sort再uniq或直接使用sort -u排序结果和预期字段不一致-k指定的列号不对或分隔符设置错误用-t明确分隔符确认字段从 1 开始编号大小写排序结果不友好默认 ASCII 码排序大写字母排在小写字母前面加-f忽略大小写输出到原文件后文件为空使用了重定向覆盖原文件导致 shell 先清空了文件使用-o选项安全输出带单位的数字排序错误sort -n不识别 K、M、G 单位使用-h选项多列排序结果不符合预期多个-k时没有指定列区间导致排序键一直延伸到行尾使用-k 2,2这样的区间限制语法5.2 详细排查为什么uniq去不掉重复这是最典型的陷阱之一。先看反例cat ips.txt | uniq由于uniq只能去除相邻的重复行而ips.txt中的重复 IP 并不相邻所以去重失败。正确做法是先排序让重复行相邻sort ips.txt | uniq或者直接一条命令sort -u ips.txt5.3 详细排查-k字段到底怎么数很多朋友写-k时不知道字段应该如何统计。这里有一个快速验证方法。假设文件内容是一行Alice:Engineering:9500执行echo Alice:Engineering:9500 | awk -F : {print $1, $2, $3}输出Alice Engineering 9500第 1 列是Alice第 2 列是Engineering第 3 列是9500。sort里的-k 3对应的就是第三列。如果分隔符不是空格-k要和-t一起使用否则sort默认按空格或制表符切分字段。5.4 详细排查空白字符导致排序异常有些数据文件每行开头或中间有多余的空格直接排序会导致结果不符合直觉。比如cat spaces.txt EOF apple banana cherry EOF sort spaces.txt由于空格参与的 ASCII 码排序空格32会排在任何字母65 以上之前。结果里带空格的apple可能排在banana前面。处理方法是加-b忽略行首空白sort -b spaces.txt如果空格在字段中间建议用-t指定分隔符或者提前用sed清理多余空格。5.5 详细排查-o和的区别简单说重定向是 shell 的功能会先创建/截断目标文件再运行命令。如果目标文件就是输入文件会让输入文件被清空。-o是sort自己的选项sort会先读取全部数据、完成排序最后再安全地写入目标文件。所以当你要把排序结果写回原文件时请使用sort -o file.txt file.txt而不是sort file.txt file.txt5.6 详细排查中文字符排序乱序遇到中文内容时sort的行为取决于系统的 locale 环境。用locale命令可以查看当前语言环境echo LANG$LANG如果LANGzh_CN.UTF-8sort会尝试按拼音顺序对中文排序如果LANGC则会按照字节顺序排序结果通常不是人们预期的拼音序或笔画序。这是很多中文数据处理场景下sort“结果不对”的常见根源。解决方案是在命令前显式指定语言环境LANGzh_CN.UTF-8 sort names.txt LANGC.UTF-8 sort names.txt前者按拼音后者按字节。具体使用哪种取决于你的业务需要。6. 最佳实践与工程建议sort虽然简单但要在真实项目中稳定、高效地使用还是有一些经验值得沉淀。6.1 优先级先 sort 再 uniq在统计场景中非常推荐把sort和uniq配对使用。但请注意执行顺序一定是先sort再uniq。原因在于uniq只能合并相邻的重复行不排序的重复行是分散在各处的。推荐写法sort input.txt | uniq -c | sort -nr如果只需要去重结果直接sort -u一步到位。6.2 写脚本时注意临时文件与性能sort在只处理小文件时速度飞快但在对几个 GB 甚至更大的日志文件进行排序时内存占用会明显上升。sort内部使用外部排序算法当数据量超过内存限制时会在临时目录中生成中间文件默认临时目录是/tmp。如果需要处理海量数据建议使用-T指定一个有足够空间的临时目录避免/tmp容量不足。尽量在脚本里用管道串行处理不要中间生成大量重复临时文件。能筛选就先筛选比如先grep过滤再sort让参与排序的数据量更小。示例sort -T /data/tmp -n huge_file.txt -o sorted_file.txt6.3 对生产日志做排序分析时先确认分隔符真实日志格式通常比较复杂字段之间存在多个空格或者制表符。比如2024-10-10 10:10:10 INFO 192.168.1.10 request_id123456 cost340ms这种情况下使用默认空格分割时多个连续空格会被忽略吗不会。sort默认把连续的空白字符当成一个字段分隔符但不同版本的 coreutils 行为略有差异。最稳妥的做法是先用awk预处理提取出目标列再交给sortawk {for(i1;iNF;i) if($i ~ /^cost/) {gsub(cost,,$i); print $i}} app.log | sort -nr | head -10这样抽取和排序分离代码可读性和健壮性都会更好。6.4 排序稳定性和多关键字排序在某些场景下排序稳定性很重要。所谓稳定性是指当两个记录排序键相等时它们的原有先后顺序是否保持不变。sort默认并不是稳定排序因为最后一次比较的规则可能会覆盖前面的结果。如果你希望保持输入顺序作为最后的兜底排序规则并开启稳定排序可以加-s选项sort -s -t : -k 2 data.txt比如先按第二个字段排序字段相同的行保持它们在原文件中的相对顺序。这在处理表格数据、保留原始序号时非常有用。更常见的做法是多关键字排序sort -t : -k 2,2 -k 3,3n employees.txt这里-k 2,2明确表示只按第 2 列排-k 3,3n表示第 3 列按数值排。这样表达意图更清晰也避免排序键延伸到行尾导致意外结果。6.5 注意安全边界覆盖源文件前文已经提到sort默认不会修改源文件有些人会误以为是安全的。但在 Shell 中sort file.txt file.txt会先清空文件再执行 sort造成数据丢失。这是一个非常危险的操作。类似的风险还出现在其他命令上比如cut file.txt file.txt、grep pattern file.txt file.txt。无论使用哪个命令凡是输出重定向到源文件都必须格外小心。建议统一使用-o完成回写或者输出到临时文件后再用mv替换原文件。6.6 利用 sort 做配置对比与校验在发布配置、更新依赖清单时经常需要比较两个文件的差异。如果不排序直接diff会因为行顺序不同产生大量无效差异。这时可以先排序再对比sort old_list.txt old_list.sorted sort new_list.txt new_list.sorted diff old_list.sorted new_list.sorted更简洁的写法diff (sort old_list.txt) (sort new_list.txt)这种方式在核对包清单、IP 白名单、域名列表时效率极高。6.7 和 find 搭配按文件名排序输出find默认输出顺序可能不固定如果希望文件名有序可以直接管道到sortfind /data/config -type f | sort在脚本里这样写可以有效避免因为文件顺序不确定导致的结果波动。6.8 日常高频组合命令速查下面几条是实际工作中几乎每天都会用到的组合命令建议保存下来# 统计访问量最高的 10 个 IP awk {print $1} access.log | sort | uniq -c | sort -nr | head -10 # 统计出现次数最多的 10 个单词 tr \n words.txt | sort | uniq -c | sort -nr | head -10 # 查看磁盘占用最大的 10 个目录 du -h --max-depth1 /data 2/dev/null | sort -hr | head -10 # 查看当前目录下最大的文件 ls -l | sort -nr -k5 | head -5 # 对 IP 列表去重并排序 sort -u ips.txt # 检查文件是否已经按数值排序 sort -n -c data.txt通过多次练习这些组合你会慢慢形成一种管道思维任何文本数据都可以拆解为“提取 → 排序 → 统计 → 展示”四个步骤。7. 总结与进一步学习方向本文围绕 Linux 系统中的sort命令从基础概念讲到高频选项再到实际登录日志分析、耗时排序、去重统计等综合案例最后整理了常见问题和工程经验。本质上sort的用法可以归纳成四个关键点默认字典排序按数值排序要加-n。多字段排序用-t指定分隔符用-k指定列。去重推荐sort -u统计推荐sort | uniq -c | sort -nr。写回源文件时使用-o而不是重定向。接下来你可以进一步学习这些相关内容uniq命令的去重与计数技巧。awk的字段切割与格式化输出。cut、tr、paste等文本处理命令。Shell 管道、进程替换与重定向机制。diff、comm等文件比较工具。在真实项目中sort往往是数据处理流水线的第一环。掌握好它的排序行为、字段规则和边界情况再配合awk和管道你就能在 Linux 终端里完成很多看似复杂的数据分析任务。希望本文对你有所帮助建议打开终端实际操作一遍印象会更加深刻。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →