如何筛选A中第二列未在B中出现的条目?Shell脚本问题排查
找出文件A中第二列未在文件B出现的整行记录
需求说明
需要提取文件A中第二列内容未在文件B中出现的整行记录,预期输出如下:
SomeFollowingText 12-45-78-54 1.1.1.1 SomeFollowingText 89-za-gg-99 4.4.4.4
文件内容
文件A
SomeFollowingText 12-45-78-54 1.1.1.1 SomeFollowingText 78-56-14-54 2.2.2.2 SomeFollowingText 52-12-98-ab 3.3.3.3 SomeFollowingText 89-za-gg-99 4.4.4.4
文件B
78-56-14-54 ab-g2-ax-47 52-12-98-ab g2-47-n7-o9 56-13-z8-ab
错误脚本排查
第一段脚本问题
awk '{print $2}' /home/path/A | while read line do if [ "grep $line /home/path/B" != "$line" ] then echo $line fi done >> /home/path/non-match
- 未执行
grep命令:这里的"grep $line /home/path/B"是字符串字面量,不是实际执行命令,和$line比较必然不相等,导致所有第二列内容都被输出。 - 仅输出第二列:需求是输出整行记录,但这段脚本只提取了第二列,不符合要求。
第二段脚本问题
cat /home/path/A | while read line do if [ "$(grep $line /home/path/B)" != "$line | awk '{print $2}'" ] then echo $line fi done >> /home/path/non-match
- 右侧是字符串而非命令:
"$line | awk '{print $2}'"是固定字符串,不是执行awk提取第二列的命令,和grep输出比较永远不相等,导致所有行都被输出。 grep $line匹配逻辑错误:用整行内容去文件B里匹配,而不是用第二列内容精确匹配,可能出现误匹配。
正确实现
方法1:用awk高效处理(推荐)
awk可以一次性加载两个文件,效率远高于循环调用grep:
awk 'NR==FNR { seen[$0]=1; next } !seen[$2]' /home/path/B /home/path/A > /home/path/non-match
- 逻辑说明:
NR==FNR:处理第一个文件(文件B)时,把每一行内容存入seen数组标记为已存在。next:跳过后续逻辑,继续处理文件B的下一行。!seen[$2]:处理文件A时,如果第二列$2不在seen数组中,就打印当前整行。
方法2:用bash循环+grep精确匹配
如果习惯用bash循环,可通过精确匹配判断:
while read -r col1 col2 rest; do # -q:静默模式不输出结果;-x:精确匹配整行;-F:把匹配内容当作普通字符串 if ! grep -qxF "$col2" /home/path/B; then echo "$col1 $col2 $rest" fi done < /home/path/A > /home/path/non-match
内容的提问来源于stack exchange,提问作者Saeed
相关产品推荐
相关产品推荐

