comm命令逐行比较两个已排序的文件,并生成三列输出:第一列显示只在第一个文件中出现的行,第二列显示只在第二个文件中出现的行,第三列显示两个文件中都存在的行。这对于分析文件差异、数据去重等场景非常有用。
comm [选项] 文件1 文件2
| 选项 | 说明 |
|---|---|
| -1 | 不输出第一列(文件1特有的行) |
| -2 | 不输出第二列(文件2特有的行) |
| -3 | 不输出第三列(两个文件共有的行) |
| --check-order | 检查输入文件是否已排序,如果没有排序则报错 |
| --nocheck-order | 不检查输入文件是否已排序(默认行为) |
| --output-delimiter=STR | 使用指定字符串作为列分隔符 |
| --help | 显示帮助信息 |
| --version | 显示版本信息 |
comm命令的输出默认分为三列,用制表符分隔:
第1列 第2列 第3列
(文件1特有) (文件2特有) (两个文件共有)
比较两个已排序的文件:
# 创建两个已排序的测试文件
echo -e "apple\nbanana\ncherry\ndate\nelderberry" > file1.txt
echo -e "banana\ncherry\ndate\nfig\ngrape" > file2.txt
# 查看文件内容
echo "文件1内容:"
cat file1.txt
echo -e "\n文件2内容:"
cat file2.txt
# 使用comm比较文件
echo -e "\ncomm比较结果:"
comm file1.txt file2.txt
输出结果:
apple
banana
cherry
date
elderberry
fig
grape
使用选项控制显示哪些列:
# 只显示两个文件共有的行
comm -12 file1.txt file2.txt
# 只显示文件1特有的行
comm -23 file1.txt file2.txt
# 只显示文件2特有的行
comm -13 file1.txt file2.txt
# 显示文件1特有和文件2特有的行(不显示共有行)
comm -3 file1.txt file2.txt | sed 's/\t//g'
对未排序的文件先进行排序再比较:
# 创建未排序的文件
echo -e "banana\napple\ncherry" > unsorted1.txt
echo -e "cherry\napple\ndate" > unsorted2.txt
# 直接比较未排序文件(结果可能不正确)
comm unsorted1.txt unsorted2.txt
# 先排序再比较
comm <(sort unsorted1.txt) <(sort unsorted2.txt)
# 或者保存排序后的文件
sort unsorted1.txt > sorted1.txt
sort unsorted2.txt > sorted2.txt
comm sorted1.txt sorted2.txt
使用自定义分隔符代替制表符:
# 使用逗号作为分隔符
comm --output-delimiter=',' file1.txt file2.txt
# 使用管道符号作为分隔符
comm --output-delimiter=' | ' file1.txt file2.txt
# 无分隔符(合并列)
comm --output-delimiter='' file1.txt file2.txt | column -t
比较两个系统的用户列表:
# 获取两个系统的用户列表(已排序)
cat /etc/passwd | cut -d: -f1 | sort > users1.txt
# 假设这是另一个系统的用户列表
cat /etc/passwd | cut -d: -f1 | sort | head -20 > users2.txt
# 比较用户列表
echo "只在系统1中的用户:"
comm -23 users1.txt users2.txt
echo -e "\n只在系统2中的用户:"
comm -13 users1.txt users2.txt
echo -e "\n两个系统共有的用户:"
comm -12 users1.txt users2.txt
使用comm进行数据分析:
# 创建测试数据
echo -e "1001\n1002\n1003\n1004\n1005" > old_customers.txt
echo -e "1002\n1003\n1005\n1006\n1007" > new_customers.txt
# 分析客户变化
echo "流失的客户:"
comm -23 old_customers.txt new_customers.txt
echo -e "\n新增的客户:"
comm -13 old_customers.txt new_customers.txt
echo -e "\n保留的客户:"
comm -12 old_customers.txt new_customers.txt
比较两个系统的配置文件差异:
#!/bin/bash
# 比较两个服务器的服务列表
compare_services() {
local server1=$1
local server2=$2
# 获取服务列表(已排序)
ssh "$server1" "systemctl list-unit-files --type=service | grep enabled | cut -d' ' -f1 | sort" > services1.txt
ssh "$server2" "systemctl list-unit-files --type=service | grep enabled | cut -d' ' -f1 | sort" > services2.txt
echo "只在 $server1 中启用的服务:"
comm -23 services1.txt services2.txt
echo -e "\n只在 $server2 中启用的服务:"
comm -13 services1.txt services2.txt
# 清理临时文件
rm services1.txt services2.txt
}
# 使用函数
compare_services "server1" "server2"
比较不同版本代码中的函数列表:
#!/bin/bash
# 提取C/C++项目中的函数名
extract_functions() {
local source_file=$1
local output_file=$2
# 简单的函数提取(实际应用可能需要更复杂的正则表达式)
grep -E '^[a-zA-Z_][a-zA-Z0-9_]*[[:space:]]+[a-zA-Z_][a-zA-Z0-9_]*\(' "$source_file" | \
sed 's/{.*//' | \
sort > "$output_file"
}
# 比较两个版本
extract_functions "version1.c" "funcs1.txt"
extract_functions "version2.c" "funcs2.txt"
echo "新增的函数:"
comm -13 funcs1.txt funcs2.txt
echo -e "\n删除的函数:"
comm -23 funcs1.txt funcs2.txt
比较数据库导出的记录:
#!/bin/bash
# 比较两个时间点的数据导出
compare_data_exports() {
local export1=$1
local export2=$2
# 确保文件已排序
sort "$export1" > "${export1}.sorted"
sort "$export2" > "${export2}.sorted"
echo "新增的记录:"
comm -13 "${export1}.sorted" "${export2}.sorted" | head -10
echo -e "\n删除的记录:"
comm -23 "${export1}.sorted" "${export2}.sorted" | head -10
echo -e "\n变更统计:"
echo "新增记录数: $(comm -13 "${export1}.sorted" "${export2}.sorted" | wc -l)"
echo "删除记录数: $(comm -23 "${export1}.sorted" "${export2}.sorted" | wc -l)"
echo "共同记录数: $(comm -12 "${export1}.sorted" "${export2}.sorted" | wc -l)"
# 清理临时文件
rm "${export1}.sorted" "${export2}.sorted"
}
# 使用函数
compare_data_exports "data_20230101.txt" "data_20230102.txt"
使用进程替换处理大型文件,避免创建临时文件:
# 使用进程替换,不创建临时文件
comm <(sort large_file1.txt) <(sort large_file2.txt)
# 结合其他命令处理输出
comm <(sort file1.txt) <(sort file2.txt) | grep -v '^$' | column -t
comm和diff命令的区别:
# comm - 逐行比较已排序文件,显示三列结果
comm file1.txt file2.txt
# diff - 显示文件差异,包括行内容变化
diff file1.txt file2.txt
# 使用diff -u获得更易读的差异
diff -u file1.txt file2.txt
使用awk处理comm的输出:
# 为不同列添加标签
comm file1.txt file2.txt | awk '
/^\t\t/ {print "共同: " $3}
/^\t[^\t]/ {print "文件2特有: " $2}
/^[^\t]/ {print "文件1特有: " $1}
'
# 统计各类行数
comm file1.txt file2.txt | awk '
/^\t\t/ {common++}
/^\t[^\t]/ {file2_only++}
/^[^\t]/ {file1_only++}
END {
print "文件1特有: " file1_only
print "文件2特有: " file2_only
print "共同: " common
}
'
确保输入文件已正确排序:
# 方法1:使用sort命令排序
sort file1.txt > file1_sorted.txt
sort file2.txt > file2_sorted.txt
comm file1_sorted.txt file2_sorted.txt
# 方法2:使用进程替换
comm <(sort file1.txt) <(sort file2.txt)
# 方法3:忽略排序检查(不推荐)
comm --nocheck-order file1.txt file2.txt
处理制表符显示问题:
# 方法1:使用自定义分隔符
comm --output-delimiter=" | " file1.txt file2.txt
# 方法2:使用column命令格式化输出
comm file1.txt file2.txt | column -t
# 方法3:使用awk重新格式化
comm file1.txt file2.txt | awk -F'\t' '{
printf "%-20s %-20s %-20s\n", $1, $2, $3
}'
确保排序和比较时正确处理空格:
# 使用稳定排序
sort -s file1.txt > file1_sorted.txt
sort -s file2.txt > file2_sorted.txt
# 或者忽略前导空格排序
sort -b file1.txt > file1_sorted.txt
sort -b file2.txt > file2_sorted.txt
# 比较时考虑整个行内容
comm file1_sorted.txt file2_sorted.txt
| 命令 | 说明 | 适用场景 |
|---|---|---|
| diff | 显示文件差异 | 需要详细差异信息,包括修改的内容 |
| sort | 文件排序 | 为comm准备输入文件 |
| uniq | 报告或忽略重复行 | 处理单个文件的重复行 |
| join | 基于共同字段连接两个文件 | 基于关键字段合并文件 |
| grep | 文本搜索 | 基于模式过滤文件内容 |