在 Bash 中,如何在一个文件中找到与另一个文件的任何行都不匹配的模式?



如何在一个文件中找到与另一个文件的任何行不匹配的模式

我知道grep有一个-f选项,所以我可以给它一个模式文件,而不是给grep一个模式。

(a。A是我的主文件)

user@system:~/test# cat a.a
Were Alexander-ZBn1gozZoEM.mp4
Will Ate-vP-2ahd8pHY.mp4

(p。P是我的模式文件)

user@system:~/test# cat p.p
ZBn1gozZoEM
0maL4cQ8zuU
vP-2ahd8pHY

命令可能是类似于

somekindofgrep p.p a.a

但是它应该给出0maL4cQ8zuU也就是模式文件中的模式,p.p,与文件a.a中的任何内容不匹配

我不知道该做什么。

$grep -f p.p a.a<ENTER>
Were Alexander-ZBn1gozZoEM.mp4
Will Ate-vP-2ahd8pHY.mp4
$

我知道如果a.a中有一个额外的行与p.p中的任何模式都不匹配,那么grep -f p.p a.a将不会显示它。如果我选择grep -v -f p.p a.a那么它只会显示a.a行,不匹配p.p

但是我有兴趣找到(我的模式文件)p.p不匹配a.a的模式!

我看着Make grep打印丢失的查询,但他想从两个文件的一切。另外,其中一个答案提到了-v,但我不认为这适用于我的情况,因为-v表示文件中不匹配任何模式的行。所以有或没有-v对我没有帮助,因为我正在寻找一个不匹配文件中任何一行的模式。

建议awk脚本扫描a.a一次:

script.awk

FNR==NR{wordsArr[$0] = 1; next} # read patterns list from 1st file into array wordsArr
{ # for each line in 2nd file
for (i in wordsArr){ # iterate over all patterns in array
if ($0 ~ i) delete wordsArr[i]; # if pattern is matched to current line remove the pattern from array
}
}
END {for (i in wordsArr) print "Unmatched: " i} # print all patterns left in wordsArray

running:script.awk

awk -f script.awk p.p a.a

测试:

p.p

aa
bb
cc
dd
ee

a.a

ddd
eee
ggg
fff
aaa

测试:

awk -f script.awk p.p a.a
Unmatched: bb
Unmatched: cc

自制脚本:

#!/bin/bash
if [[ $# -eq 2 ]]
then
patterns="$1"
mainfile="$2"
if [[ ! -f "$patterns" ]]
then
echo "ERROR: file $patterns does not exist."
exit 1
fi
if [[ ! -f "$mainfile" ]]
then
echo "ERROR: file $mainfile does not exist."
exit 1
fi
else
echo "Usage: $0 <PATTERNS FILE> <MAIN FILE>"
exit 1
fi
while IFS= read -r pattern
do
if [[ ! grep -q "$pattern" "$mainfile" ]]
then
echo "$pattern"
fi
done < "$patterns"

就像user1934428建议的那样,这个脚本在文件p.p中的模式上循环,并打印出文件a.a中没有找到的任何模式。

# grep p.p pattern in a.a and output pattern 
# if grep is true (pattern matched in a.a)
xargs -i sh -c 'grep -q "{}" a.a && echo "{}"' < p.p
# if grep is false (pattern NOT matched in a.a <--- what you need)
xargs -i sh -c 'grep -q "{}" a.a || echo "{}"' < p.p

这是一个可能的解决方案,基于你想要做的事情的一个可能的解释(在p.p的行上对-a.a行中最后一个.之间的子字符串的完整字符串匹配):

$ awk '
NR==FNR {
sub(/[^-]*-/,"")
sub(/.[^.]*$/,"")
file1[$0]
next
}
!($0 in file1)
' a.a p.p
0maL4cQ8zuU

在每个Unix机器的任何shell中使用任何awk都可以健壮地、可移植地、高效地工作。它的运行速度将比当前的shell循环答案快几个数量级,比现有的awk答案或xargs答案快,并且无论文件中存在哪些字符(包括regexp元字符),以及p.p中的搜索字符串是否作为子字符串或a.a中的其他上下文中存在,它都可以工作。无论输入文件中有什么内容,它都不会有任何安全问题。

相关内容

最新更新