sort 命令详解与参数实测(Ubuntu 22.04)
sort 命令逐参数实测:字典序与 locale 影响、-n/-r/-u/-h/-g/-R/-c/-o/-m 与 -k/-t 键位定制、LC_ALL=C 惯用法,全部回显在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。
sort 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 GNU sort 的排序规则与每一个常用参数——默认字典序与 locale 影响、
-n/-r/-u/-h/-g/-R/-c/-o/-m各参数行为、-k/-t键位与分隔符定制,以及LC_ALL=C sort惯用法,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。
一、环境信息
本节记录实测环境与测试数据,便于读者按相同条件复现本文全部命令与回显。
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- sort 版本:GNU coreutils 8.32(
sort --version实测) - 默认 locale:
LANG未设置(等效 C locale);为做 locale 对照实验,已预先安装locales包并用locale-gen生成en_US.UTF-8 - 实测工作目录:
/root/demo/sort/ - 测试数据:
fruits.txt(大小写混合的水果名单,含重复行)、nums.txt(整数列表)、scores.txt(空格分隔的姓名分数)、users.csv(4 列 CSV)、sizes.txt(du -h 风格大小与目录名)、sci.txt(科学计数法数值)、part1.txt/part2.txt(两个已排序分片)
二、命令概览
2.1 语法与测试数据准备
sort 的基本语法为 sort [OPTION]... [FILE]...:对所有 FILE 的行排序后输出,无 FILE 或 FILE 为 - 时读标准输入。测试前先准备一套演示文件,后续所有参数实测都基于这套数据:
mkdir -p /root/demo/sort
cat > /root/demo/sort/fruits.txt <<'EOF'
cherry
apple
Banana
apple
Apricot
banana
EOF
cat > /root/demo/sort/nums.txt <<'EOF'
10
9
100
2
1
EOF
cat > /root/demo/sort/scores.txt <<'EOF'
alice 88
bob 9
carol 105
dave 66
EOF
cat > /root/demo/sort/users.csv <<'EOF'
name,dept,age,city
alice,dev,28,Beijing
bob,ops,32,Shanghai
carol,dev,26,Shenzhen
dave,qa,30,Guangzhou
EOF
cat > /root/demo/sort/sizes.txt <<'EOF'
4.0K tmp
1.5M logs
300G backup
20M cache
8.0K conf
EOF
cat > /root/demo/sort/sci.txt <<'EOF'
1e3
2.5e-1
100
-5e2
0.07
EOF
cat > /root/demo/sort/part1.txt <<'EOF'
1
3
5
EOF
cat > /root/demo/sort/part2.txt <<'EOF'
2
4
6
EOF
验证数据就绪(nums.txt 未排序、part1.txt/part2.txt 已各自有序,供 3.10 与 3.13 节使用):
$ ls -l /root/demo/sort
total 32
-rw-r--r-- 1 root root 41 Oct 15 07:40 fruits.txt
-rw-r--r-- 1 root root 13 Oct 15 07:40 nums.txt
-rw-r--r-- 1 root root 6 Oct 15 07:40 part1.txt
-rw-r--r-- 1 root root 6 Oct 15 07:40 part2.txt
-rw-r--r-- 1 root root 25 Oct 15 07:40 sci.txt
-rw-r--r-- 1 root root 33 Oct 15 07:40 scores.txt
-rw-r--r-- 1 root root 51 Oct 15 07:40 sizes.txt
-rw-r--r-- 1 root root 103 Oct 15 07:40 users.csv
$ cat /root/demo/sort/fruits.txt
cherry
apple
Banana
apple
Apricot
banana
$ echo LANG=$LANG
LANG=
$ locale -a | grep -iE "en_US|^C$"
C
en_US.utf8
💡 说明:
LANG为空表示默认按 C locale 处理——sort 的字典序直接由 locale 决定,同一份数据在不同 locale 下排序结果可能不同,3.2 节将做专门对照。
2.2 --help 全量回显
sort --help 输出全部参数清单(实测原样保留,可作为参数速查):
Usage: sort [OPTION]... [FILE]...
or: sort [OPTION]... --files0-from=F
Write sorted concatenation of all FILE(s) to standard output.
With no FILE, or when FILE is -, read standard input.
Mandatory arguments to long options are mandatory for short options too.
Ordering options:
-b, --ignore-leading-blanks ignore leading blanks
-d, --dictionary-order consider only blanks and alphanumeric characters
-f, --ignore-case fold lower case to upper case characters
-g, --general-numeric-sort compare according to general numerical value
-i, --ignore-nonprinting consider only printable characters
-M, --month-sort compare (unknown) < 'JAN' < ... < 'DEC'
-h, --human-numeric-sort compare human readable numbers (e.g., 2K 1G)
-n, --numeric-sort compare according to string numerical value
-R, --random-sort shuffle, but group identical keys. See shuf(1)
--random-source=FILE get random bytes from FILE
-r, --reverse reverse the result of comparisons
--sort=WORD sort according to WORD:
general-numeric -g, human-numeric -h, month -M,
numeric -n, random -R, version -V
-V, --version-sort natural sort of (version) numbers within text
Other options:
--batch-size=NMERGE merge at most NMERGE inputs at once;
for more use temp files
-c, --check, --check=diagnose-first check for sorted input; do not sort
-C, --check=quiet, --check=silent like -c, but do not report first bad line
--compress-program=PROG compress temporaries with PROG;
decompress them with PROG -d
--debug annotate the part of the line used to sort,
and warn about questionable usage to stderr
--files0-from=F read input from the files specified by
NUL-terminated names in file F;
If F is - then read names from standard input
-k, --key=KEYDEF sort via a key; KEYDEF gives location and type
-m, --merge merge already sorted files; do not sort
-o, --output=FILE write result to FILE instead of standard output
-s, --stable stabilize sort by disabling last-resort comparison
-S, --buffer-size=SIZE use SIZE for main memory buffer
-t, --field-separator=SEP use SEP instead of non-blank to blank transition
-T, --temporary-directory=DIR use DIR for temporaries, not $TMPDIR or /tmp;
multiple options specify multiple directories
--parallel=N change the number of sorts run concurrently to N
-u, --unique with -c, check for strict ordering;
without -c, output only the first of an equal run
-z, --zero-terminated line delimiter is NUL, not newline
--help display this help and exit
--version output version information and exit
KEYDEF is F[.C][OPTS][,F[.C][OPTS]] for start and stop position, where F is a
field number and C a character position in the field; both are origin 1, and
the stop position defaults to the line's end. If neither -t nor -b is in
effect, characters in a field are counted from the beginning of the preceding
whitespace. OPTS is one or more single-letter ordering options [bdfgiMhnRrV],
which override global ordering options for that key. If no key is given, use
the entire line as the key. Use --debug to diagnose incorrect key usage.
SIZE may be followed by the following multiplicative suffixes:
% 1% of memory, b 1, K 1024 (default), and so on for M, G, T, P, E, Z, Y.
*** WARNING ***
The locale specified by the environment affects sort order.
Set LC_ALL=C to get the traditional sort order that uses
native byte values.
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/sort>
or available locally via: info '(coreutils) sort invocation'
💡 说明:帮助末尾的 WARNING 官方直接点明了本文最重要的一条实践——locale 影响排序结果,
LC_ALL=C可获得按原生字节值排序的传统行为。-k键定义F[.C][OPTS]的完整语法也在帮助中给出,3.6 与 3.7 节将实测其中最常用的两种。
2.3 版本确认
$ sort --version | head -1
sort (GNU coreutils) 8.32
三、参数逐项实测
本章逐项实测每个参数:每节先给命令与真实回显,再解释行为要点。
3.1 默认字典序:C locale 下大写在前
不带参数时 sort 按当前 locale 的字典序对整行排序:
$ sort /root/demo/sort/fruits.txt
Apricot
Banana
apple
apple
banana
cherry
当前环境 LANG 未设置,等效 C locale:按字节值比较,大写字母(0x41 起)全部排在小写字母(0x61 起)之前,所以 Apricot、Banana 排在最前;两行 apple 是完全相同的行,相邻保留。
3.2 locale 对字典序的影响与 LC_ALL=C 惯用法
同一文件换 locale 排序,结果不同:
$ LC_ALL=C sort /root/demo/sort/fruits.txt
Apricot
Banana
apple
apple
banana
cherry
$ LC_ALL=en_US.UTF-8 sort /root/demo/sort/fruits.txt
apple
apple
Apricot
banana
Banana
cherry
LC_ALL=C:逐字节比较,与 3.1 节默认结果一致(本环境默认即 C locale);LC_ALL=en_US.UTF-8:词典序,大小写差异被弱化为次级比较,先按字母排序(apple、banana、cherry),同字母组内再区分大小写(apple 在 Apricot 前、banana 在 Banana 前)。
💡 提示:
LC_ALL=C sort是 shell 脚本中的标准惯用法——它把排序锚定在字节值上,不随部署环境的 locale 变化,保证脚本输出可预期;LC_ALL的优先级高于LANG,适合临时覆盖。反之,面向人阅读的名单类排序可保留系统 locale 获得更自然的词典序。
3.3 -n:数值排序
默认字典序对数字是「按字符比」,10、100 会排在 2 之前;-n 按字符串表示的数值比较:
$ sort /root/demo/sort/nums.txt
1
10
100
2
9
$ sort -n /root/demo/sort/nums.txt
1
2
9
10
100
第一条是默认字典序:逐字符比较 1 < 2 < 9,所以 10、100 紧跟在 1 后面。第二条 -n 才是数值 1 < 2 < 9 < 10 < 100 的正确顺序。凡排序对象是数字,必须加 -n。
3.4 -r:反向排序
-r 反转比较结果,可单独用,也可与 -n 组合:
$ sort -r /root/demo/sort/nums.txt
9
2
100
10
1
$ sort -nr /root/demo/sort/nums.txt
100
10
9
2
1
第一条是字典序的倒序(9 最大因为字符 9 最大),第二条 sort -nr 才是「从大到小」的数值倒序——排查 TopN 问题(如取消耗最高的前几行)用 -nr 再配合 head。
3.5 -u:排序并去重
-u 在排序后只保留相等行中的第一行:
$ sort -u /root/demo/sort/fruits.txt
Apricot
Banana
apple
banana
cherry
6 行输入输出 5 行:两行 apple 被去重;Banana 与 banana 因大小写不同在 C locale 下是两个不同字符串,都保留。用管道把计数过程摆出来看得更清楚:
$ sort /root/demo/sort/fruits.txt | uniq -c
1 Apricot
1 Banana
2 apple
1 banana
1 cherry
sort -u 等价于 sort | uniq(详见《uniq 命令详解与参数实测(Ubuntu 22.04)》),一步完成且少起一个进程。
💡 技术拓展:排序结果里「值相等的行谁排前面」由排序稳定性决定,这是所有排序实现的通用概念——
概念 含义 在 GNU sort 中的体现 稳定排序 相等行保持原输入的先后顺序 默认排序算法本身稳定,但默认还叠加整行「最后手段比较」 最后手段比较 键相等时再比整行字节 默认开启,导致相等键的顺序仍可能被打散 -s, --stable关闭最后手段比较 键相等的行严格保持输入顺序,适合多轮 -k排序本文示例按默认行为演示;需要「先按 A 排、再按 B 排」的多键叠加场景,推荐
sort -s -k2,2 | sort -s -k1,1这类稳定排序管线,或一次给出多个-k。
3.6 -k2 与 -k2,2n:按第 2 列排序
-k 指定排序键,格式 F[.C][OPTS][,F[.C][OPTS]]。-k2 表示从第 2 字段比到行尾(字符串比较):
$ sort -k2 /root/demo/sort/scores.txt
carol 105
dave 66
alice 88
bob 9
$ sort -k2,2n /root/demo/sort/scores.txt
bob 9
dave 66
alice 88
carol 105
-k2:键是88、9、105、66这些字符串,字典序下1<6<8<9,得到 carol、dave、alice、bob——分数 9 的 bob 反而垫底;-k2,2n:逗号后的,2把键限定在第 2 字段本身(F.C,FC的起点.字符与终点写法),修饰符n对该键启用数值比较,得到 9 < 66 < 88 < 105 的正确顺序。
键定义里不写终止位置时键延伸到行尾,这是 -k2 与 -k2,2n 结果迥异的原因,也是 -k 最常见的误用点。
3.7 -t:自定义字段分隔符(CSV 按列排)
默认字段分隔符是「非空白到空白的过渡」,CSV 这类逗号数据需要 -t 显式指定:
$ sort -t, -k2 /root/demo/sort/users.csv
name,dept,age,city
carol,dev,26,Shenzhen
alice,dev,28,Beijing
bob,ops,32,Shanghai
dave,qa,30,Guangzhou
$ sort -t, -k3,3n /root/demo/sort/users.csv
name,dept,age,city
carol,dev,26,Shenzhen
alice,dev,28,Beijing
dave,qa,30,Guangzhou
bob,ops,32,Shanghai
-t, -k2:按第 2 字段(部门)起的整行字符串排序,dev 组内再按年龄字符比出dev,26在dev,28之前,表头dept因p<v排在所有数据行之前;-t, -k3,3n:把键限定在第 3 字段并启用数值比较,表头age按数值 0 排在最前,数据按 26 < 28 < 30 < 32 升序。
CSV 排序模板记这两条即可:sort -t, -kN 按第 N 列字符串排、sort -t, -kN,Nn 按第 N 列数值排。
3.8 -h:人类可读大小排序
du -h、ls -lh 输出的 4.0K、1.5M、300G 是带单位后缀的「人类可读数」,必须用 -h 才能比出真实大小:
$ sort /root/demo/sort/sizes.txt
1.5M logs
20M cache
300G backup
4.0K tmp
8.0K conf
$ sort -h /root/demo/sort/sizes.txt
4.0K tmp
8.0K conf
1.5M logs
20M cache
300G backup
默认字典序把 300G 排在 4.0K 前面,显然错误;-h 按 K < M < G 的数量级还原真实大小排序。du -h 目录 | sort -h 因此成为「找出最占空间目录」的标准管线。
3.9 -g:通用数值排序(支持科学计数法)
-n 只解析前导数字,1e3 会被当成 1;-g 按完整浮点值(strtol/strtod 语义)比较,支持科学计数法与负数:
$ sort -n /root/demo/sort/sci.txt
-5e2
0.07
1e3
2.5e-1
100
$ sort -g /root/demo/sort/sci.txt
-5e2
0.07
2.5e-1
100
1e3
-n 把 1e3 当 1、2.5e-1 当 2.5,得到 1 < 2.5 < 100 的错序(1e3 插在 0.07 与 2.5e-1 之间);-g 还原真实值 -500 < 0.07 < 0.25 < 100 < 1000。普通整数用 -n 足够且更快,含小数点、科学计数法、NaN/Infinity 的数据用 -g。
3.10 -c:检查文件是否已排序
-c 不排序,只检查输入是否有序:已序静默返回退出码 0,未序向 stderr 报告第一处乱序并返回 1:
$ sort -c /root/demo/sort/nums.txt; echo exit=$?
sort: /root/demo/sort/nums.txt:3: disorder: 100
exit=1
$ sort -c /root/demo/sort/part1.txt; echo exit=$?
exit=0
nums.txt 第 3 行 100 按字典序应排在第 2 行 9 之前,故报告 3: disorder: 100;part1.txt 已有序,无输出、退出码 0。常用于脚本前置校验(配合 -C 静默版)或校验大型归并管线的前置条件。
3.11 -o:结果写入文件(支持原地排序)
-o 把排序结果写入指定文件,且允许输出文件与输入文件同名——这是它优于重定向 > 的地方:
$ sort -n -o /root/demo/sort/nums_sorted.txt /root/demo/sort/nums.txt
$ cat /root/demo/sort/nums_sorted.txt
1
2
9
10
100
$ sort -n -o /root/demo/sort/nums.txt /root/demo/sort/nums.txt
$ cat /root/demo/sort/nums.txt
1
2
9
10
100
第一条写入新文件;第二条输入输出同名,sort 先读完输入再写回,文件被安全地「原地排序」。若改用 sort -n nums.txt > nums.txt,shell 会先清空输出文件导致数据丢失,这是必须用 -o 的根本原因。
3.12 -R:随机排序(洗牌)
-R 按随机键打散相同键的行,两次运行顺序不同:
$ sort -R /root/demo/sort/fruits.txt
Banana
apple
apple
cherry
Apricot
banana
$ sort -R /root/demo/sort/fruits.txt
banana
cherry
Apricot
apple
apple
Banana
两次输出顺序都不一样(随机种子来自系统随机源),但相同行(两行 apple)始终相邻——-R 的语义是「洗牌但相同键归组」。需要可复现的随机序列时用 --random-source=文件 固定随机源(见 2.2 帮助原文);纯粹的随机抽样可考虑专用工具 shuf。
3.13 -m:归并已排序文件
-m 假定各输入文件已有序,直接做归并(merge),不再排序:
$ sort -m /root/demo/sort/part1.txt /root/demo/sort/part2.txt
1
2
3
4
5
6
$ cat /root/demo/sort/part1.txt /root/demo/sort/part2.txt
1
3
5
2
4
6
两个各含 3 行的有序分片被交错归并成完整有序序列。对比 cat 的拼接输出可看出差别:-m 输出全局有序。归并只做线性扫描,比重新排序省得多,适合把多个分块排序结果(如 split 切片、并行任务输出)合成一个有序大文件的场景;若输入其实无序,-m 不会纠正,结果是错的。
四、实战示例
前面各节覆盖了单个参数的行为,本节给四个可直接套用的组合场景。
1. 找出最占空间的目录——du -h 风格数据交给 sort -h:
$ sort -h /root/demo/sort/sizes.txt
4.0K tmp
8.0K conf
1.5M logs
20M cache
300G backup
2. TopN 榜单——数值倒序后用 head 截取前几名(这里演示完整倒序输出):
$ sort -nr /root/demo/sort/nums.txt
100
10
9
2
1
3. 按部门归组查看员工表——CSV 指定逗号分隔符、按第 2 列排:
$ sort -t, -k2 /root/demo/sort/users.csv
name,dept,age,city
carol,dev,26,Shenzhen
alice,dev,28,Beijing
bob,ops,32,Shanghai
dave,qa,30,Guangzhou
4. 脚本中校验上游数据有序——-c 借助退出码做断言:
$ sort -c /root/demo/sort/part1.txt; echo exit=$?
exit=0
五、注意事项与常见问题
本节汇总 sort 使用中最容易踩坑的四类问题,均对应前文实测结论。
Q1:为什么 10 排在 2 前面?
默认字典序逐字符比较,10 的第 1 个字符 1 小于 2,所以 10、100 都排在 2 前(3.3 节实测)。数字列一律加 -n;带 K/M/G 单位加 -h;科学计数法加 -g。
Q2:同一份文件在不同机器上排序结果不一样?
locale 不同导致字典序不同(3.2 节实测:C 与 en_US.UTF-8 结果迥异)。脚本与流水线中显式写 LC_ALL=C sort 锚定字节序;sort --help 末尾的官方 WARNING 也是同样建议。
Q3:sort -u 与 uniq 有什么区别?
sort -u 等价于 sort | uniq:先全局排序再相邻去重。差别在效率与语义——sort -u 一步完成;uniq 单独使用只能合并相邻重复行(不排序时去重不完整),必须先 sort。需要对「去重键」精细控制(忽略大小写、跳过字段)时用 sort | uniq -i/-f/-w 组合。
Q4:-k2 和 -k2,2n 有什么区别?
-k2 的键从第 2 字段延伸到行尾且按字符串比较;-k2,2n 把键限定在第 2 字段本身并启用数值比较(3.6 节实测两者结果完全不同)。经验法则:-kN 起头会「连累」后面的列参与比较,精确控制用 -kN,N,数值列再加 n。
六、参考链接
- GNU Coreutils 官方手册 sort 章节:https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html
- Ubuntu 22.04 (jammy) 在线 man 手册 sort(1):https://manpages.ubuntu.com/manpages/jammy/en/man1/sort.1.html
- GNU C 库 locale 文档(glibc):https://www.gnu.org/software/libc/manual/html_node/Locales.html
- 本系列关联篇:《uniq 命令详解与参数实测(Ubuntu 22.04)》《cut 命令详解与参数实测(Ubuntu 22.04)》