Shell 命令行求两个文件每行对比的相同内容
遇到的一个实际问题是,2017年08月01日起,所有未经实名的域名,全部停止解析。而我手上有不少域名,其中很多都是没有实名的。但我不知道哪些实名了,哪些没有实名。所以,我搞到了两个文件:
- 我的上级代理商的所有未实名的域名列表
- 我的所有域名列表
现在,我需要得到的是,我的域名在所有未实名域名列表中出现的个数。
两层 while 循环求合集
事实上我解决这个问题是用js解决的。把两个文件构建成数组之后,通过两层循环对比,就输出了我想要的结果。
但这不是学习shell嘛,尝试用同样的思路,用shell解决。
代码如下:
cat b.txt | while read lineb
do
cat a.txt | while read linea
do
if [ $lineb -eq $linea ]
then
echo $lineb
fi
done
done
逻辑非常简单。两层while循环,对比就可以完成了。
两层 for 循环求合集
上面查了一下用 while read
这种方式读取每一行,所以用了 while
这种循环方法。事实上,用 for
循环也一样可以做到,所以,代码如下:
for i in $(cat b.txt); do
for j in $(cat a.txt); do
if [ $j -eq $i ]
then
echo $i
fi
done
done
逻辑是一模一样的。
一层 for 循环加 grep 求合集
好了,上面都是逻辑非常简单的处理。那么有没有可能用一层的循环来解决问题呢?
答案是可以的。我们需要用到 grep
这个牛逼的工具。 grep
是一个强大的文本搜索工具,可以匹配正则来进行搜索。
那么逻辑就非常简单了。循环其中一个文件,把每一行的内容利用 grep
正则匹配另一个文件,如果有匹配,则输出。
代码如下:
for i in $(cat b.txt); do
grep "\<$i\>" a.txt
done
因为 grep
命令是把符合的输出出来,所以没必要 echo
一下了。
不用循环求合集
上面的几种方法,都使用了循环来解决问题。都是比较符合我们的编程直觉的。但是,我们可以不可以不使用循环来解决问题呢?
答案是可以的,我找到了一个牛逼的命令 comm
这个命令的解释是 select or reject lines common to two files
,可以用于两个文件之间的比较,它有一些选项可以用来调整输出,以便执行交集、求差、以及差集操作。
好,我们直接上手这个命令试试
comm a.txt b.txt
直接干了一下,发现好像不成。先要排序以及去重才行。
所以,修改命令如下:
comm <(sort a.txt|uniq) <(sort b.txt|uniq)
执行结果如下:
1 11 12 2 3 4 5 6 7 8 9
第一列表示第一个文件独有的内容,第二列表示第二个文件独有的内容,第三列是共有的内容,也就是合集。
comm -12 <(sort a.txt|uniq) <(sort b.txt|uniq)
其他补充
- 在
unix
思想中,一个程序只做一件事情。而我们把一个内容要进行去重处理,就必须进行两个操作:
- 首先进行排序操作
sort
- 然后把相邻并且相同的内容给去重
uniq
- 首先进行排序操作
- 当我们不知道一个命令是干嘛的时候,可以用
whatis xxx
来进行查询 - 当
whatis
不能满足我们的需求的时候,我们使用man xxx
来进行更加详细的查看。 - 我们写的
*.sh
文件如果希望直接运行,可以用chmod +x *.sh
来赋予*.sh
直接运行的权限。之后可以用./*.sh
来执行 - 如果随便写写,不要求运行权限,可以
sh *.sh
来运行脚本 - 这两种运行的结果是有差异的,具体自行参考这里。
本文有 FungLeo 原创,允许转载,但转载必须保留首发链接。