偶然间读到文章程序员,你真的会用 Unix 命令?时, 发现了这个comm
命令.
comm --help
:
Compare sorted files FILE1 and FILE2 line by line
意思是说, comm
这个命令可以逐行比较两个排序过的文件
话不多说, 看个示例:
# 测试文件1
[root@localhost ~]# cat int1.txt
01
02
03
04
05
# 测试文件2
[root@localhost ~]# cat int2.txt
01
02
03
04
06
# 执行测试
[root@localhost ~]# comm int1.txt int2.txt
01
02
03
04
05
06
可以看到, comm默认生成三列结果, 第一列是文件1独有的, 第二列是文件2独有的, 第三列是两个文件共有的.
但是如果有一个或者两个都没有排序怎么办呢?
如把int1.txt改成下面这样的:
[root@localhost ~]# cat int1.txt
02
03
04
05
01
再执行:
[root@localhost ~]# comm int1.txt int2.txt
01
02
03
04
05
comm: file 1 is not in sorted order
01
06
发现有警告说文件1没有排序.
这可如何是好, 可以试试sort
命令, 发现又是正确的结果啦:
[root@localhost ~]# comm <(cat int1.txt | sort) int2.txt
01
02
03
04
05
06
输出有三列, 那如果我们只想取其中一列呢? 比如我们只想取共有的, 也就是交集:
查查帮助(comm --help
)可知:
-1 suppress column 1 (lines unique to FILE1)
-2 suppress column 2 (lines unique to FILE2)
-3 suppress column 3 (lines that appear in both files)
可以通过-1, -2, -3来指定不显示哪一列. 那么只显示共有的, 就是:
[root@localhost ~]# comm -1 -2 <(cat int1.txt | sort) int2.txt
01
02
03
04
求交集可以这样来实现(一时心血来潮想写一下):
思路, 先给两个序列排序(sort
), 再循环, 移动指针放入新数组中
#!/bin/bash
arr1=()
arr2=()
file1="$1"
file2="$2"
i=0
# 注意这里不能用管道给`while read`传递, 因为那样会起子shell, 会导致arr1在外边读不到
while read line; do
if [[ -z "$line" ]]; then
continue
fi
arr1[$i]="$line"
i=$(($i+1))
done < <(cat "$file1" | sort)
i=0
while read line; do
if [[ -z "$line" ]]; then
continue
fi
arr2[$i]="$line"
i=$(($i+1))
done < <(cat "$file2" | sort)
# echo "arr1=${arr1[*]}"
# echo "arr2=${arr2[*]}"
len1=${#arr1[*]}
len2=${#arr2[*]}
arr3=()
k=0
for ((i=0, j=0; i < len1 && j < len2; true)); do
t1=${arr1[i]}
t2=${arr2[j]}
if [[ "$t1" == "$t2" ]]; then
i=`expr $i + 1` # i++
j=`expr $j + 1` # j++
arr3[k]=$t1
k=`expr $k + 1`
elif [[ "$t1" > "$t2" ]]; then
j=`expr $j + 1`
else
i=`expr $i + 1`
fi
done
for i in "${!arr3[@]}"; do
echo ${arr3[i]}
done
另存为comm.sh
, 还是用刚才的测试文件, 执行来看看
[root@localhost ~]# bash comm.sh int1.txt int2.txt
01
02
03
04
欢迎补充指正!