comm 必须配合 lc_all=c sort 预处理,否则因 locale 不一致导致行序错位;输出三列以制表符分隔,-1/-2/-3 控制显示列,且不自动 trim 空白或处理制表符,适用场景有限。

comm 不是 diff,它不校验排序、不自动排序、不处理乱序输入——直接跑 comm file1 file2 很可能输出错漏结果,甚至漏掉关键差异。必须先排序、再比对、再选列。
comm 前必须用 LC_ALL=C sort 预处理
Linux 默认 locale(比如 en_US.UTF-8)会让 sort 把中文、标点、大小写按语言规则排,而 comm 默认也走同一套规则;但一旦两文件用不同 locale 排序,或一个没指定 locale,行序就错位,comm 会把本该相同的行判成“仅 file1 有”。
- 统一用
LC_ALL=C sort file1 > file1.sorted和LC_ALL=C sort file2 > file2.sorted - 验证是否真排好:
sort -c file1.sorted(无输出才表示合规) - 别写
sort file1 | comm - file2.sorted—— pipe 中任意一端失败,comm就读到截断数据,静默出错
理解三列输出和 -1/-2/-3 的真实含义
comm 默认输出三列,用制表符 \t 分隔,肉眼几乎分不清哪列是哪列。第 1 列 ≠ “file1 独有”,而是“只在 file1.sorted 中出现的行”;第 2 列同理;第 3 列是交集。
-
comm -13 file1.sorted file2.sorted→ 只显示第 2 列:即“只在 file2.sorted 中有”的行(file2 减 file1) -
comm -23 file1.sorted file2.sorted→ 只显示第 1 列:即“只在 file1.sorted 中有”的行(file1 减 file2) -
comm -12 file1.sorted file2.sorted→ 只显示第 3 列:交集,等价于共有行 - 别信网上写的
comm -i:GNU 版本虽支持-i(忽略大小写),但多数系统不带,且行为不稳定,建议先用tr 'A-Z' 'a-z'统一小写再排序
前导空白和空格会让比较失效
comm 按整行字面值比对,不 trim、不 normalize。"hello" 和 " hello"(前面多个空格)会被判为不同行,哪怕语义一致。
- 若需忽略前导空白:
sort -k1,1b file1 | comm -12 - file2.sorted(bflag 跳过 leading blanks) - 若需彻底清理首尾空白:
sed 's/^[[:space:]]*//; s/[[:space:]]*$//' file1 | LC_ALL=C sort > file1.clean - 别依赖
comm -d(部分 GNU 版本支持,但结果不可靠)——它只是跳过排序检查,并不帮你重排
什么情况下不该硬用 comm
当文件含制表符、字段需按列比对、或要定位某一行在哪一列改了内容时,comm 就不是合适工具。
- 字段级对比(如 CSV 第 2 列):先用
cut -f2提取再comm,或直接用join - 超大文件(>1GB):
sort内存占用高,comm仍需全加载,不如sort file1 file2 | uniq -u流式处理 - 需要上下文(比如“这一行删了,下一行加了”):换
diff -u,comm只管行存在与否,不管位置变动
真正容易被忽略的是 locale 一致性——哪怕你记得排序,忘了 LC_ALL=C,中文或带符号的行就大概率错位;还有就是三列输出默认用 \t 分隔,不加 cat -A 或重定向到文件再用编辑器看,根本看不出哪列是哪列。











