在 bash 中,如何在一个文件中找到与另一个文件的任何行都不匹配的模式?
in bash, how can I find a pattern in one file that doesn't match any line of another file?
如何在一个文件中找到与另一个文件的任何行都不匹配的模式
我知道 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 print missing queries,但他想要两个文件中的所有内容。而且,那里的答案之一提到了 -v 但我不太明白它适用于我的案例,因为 -v 显示了与任何模式都不匹配的文件行。所以有或没有 -v 对我没有帮助,因为我正在寻找一个与文件的任何行都不匹配的模式。
自制脚本:
#!/bin/bash
if [[ $# -eq 2 ]]
then
patterns=""
mainfile=""
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: [=10=] <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
.
中未找到的任何模式
建议 awk
扫描 a.a
一次的脚本:
script.awk
FNR==NR{wordsArr[[=10=]] = 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 ([=10=] ~ 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
运行: 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
# 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
这是一个可能的解决方案,它基于对您正在尝试执行的操作的一种可能解释(full-string 匹配 p.p
中的行与第一个 [=12] 之间的子字符串=] 和 a.a
行中的最后一个 .
):
$ awk '
NR==FNR {
sub(/[^-]*-/,"")
sub(/\.[^.]*$/,"")
file1[[=10=]]
next
}
!([=10=] in file1)
' a.a p.p
0maL4cQ8zuU
以上内容将在每个 Unix 机器上使用任何 shell 中的任何 awk 稳健、可移植且高效地工作。它会比当前的 shell 循环答案快 运行 个数量级,比现有的 awk 答案或 xargs 答案快,并且无论哪个文件中存在哪个字符都可以工作,包括正则表达式元字符, p.p
中的搜索字符串是否作为子字符串或在 a.a
的其他上下文中存在。无论输入文件中有什么,它也将具有零安全问题。
如何在一个文件中找到与另一个文件的任何行都不匹配的模式
我知道 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 print missing queries,但他想要两个文件中的所有内容。而且,那里的答案之一提到了 -v 但我不太明白它适用于我的案例,因为 -v 显示了与任何模式都不匹配的文件行。所以有或没有 -v 对我没有帮助,因为我正在寻找一个与文件的任何行都不匹配的模式。
自制脚本:
#!/bin/bash
if [[ $# -eq 2 ]]
then
patterns=""
mainfile=""
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: [=10=] <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
.
建议 awk
扫描 a.a
一次的脚本:
script.awk
FNR==NR{wordsArr[[=10=]] = 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 ([=10=] ~ 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
运行: 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
# 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
这是一个可能的解决方案,它基于对您正在尝试执行的操作的一种可能解释(full-string 匹配 p.p
中的行与第一个 [=12] 之间的子字符串=] 和 a.a
行中的最后一个 .
):
$ awk '
NR==FNR {
sub(/[^-]*-/,"")
sub(/\.[^.]*$/,"")
file1[[=10=]]
next
}
!([=10=] in file1)
' a.a p.p
0maL4cQ8zuU
以上内容将在每个 Unix 机器上使用任何 shell 中的任何 awk 稳健、可移植且高效地工作。它会比当前的 shell 循环答案快 运行 个数量级,比现有的 awk 答案或 xargs 答案快,并且无论哪个文件中存在哪个字符都可以工作,包括正则表达式元字符, p.p
中的搜索字符串是否作为子字符串或在 a.a
的其他上下文中存在。无论输入文件中有什么,它也将具有零安全问题。