linux命令之 comm 使用

偶然间读到文章程序员,你真的会用 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

欢迎补充指正!

发布了232 篇原创文章 · 获赞 78 · 访问量 52万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览