我希望能够使用管道输入的域参考文件或参考文件(文件B )从文件A
例如,我不能使用grep "bbc.co.uk"
,因为它将包括诸如cbbc.co.uk
之类的条目。
我尝试使用while读取循环来遍历文件B ,运行grep -E "^([^.\s]+\.)*${escaped_domain}$" fileA
来识别域和子域,但这非常慢,因为需要进行比较
有更好的方法吗?也许使用awk?
文件B(或管道输入)
〜3万行
bbc.co.uk
amazon.co.uk
doubleclick.net
文件A
〜150k +线
123123.test.bbc.co.uk
123434.rwr.amazon.co.uk
ads.bbc.co.uk
adsa.23432.doubleclick.net
amazon.co.uk
bbc.co.uk
cbbc.co.uk
damazon.co.uk
fsdfsfs.doubleclick.net
test.amazon.co.uk
test.bbc.co.uk
test.damazon.co.uk
所需的输出:
cbbc.co.uk
damazon.co.uk
test.damazon.co.uk
当前方法(与grep / regexps不同的输入)
# Convert input: address=/test.com/ -> ^([^.\s]+\.)*test\.com$
regexList=$(cat fileB |
sed 's/\./\\./g' |
awk -F '/' {'print "^([^.\s]+\.)*"$2"$"'})
while read -r regex; do
grep -E $regex filaA
done <<< "$regexList"
答案 0 :(得分:2)
$ awk '
NR==FNR {
gsub(/[^^]/,"[&]")
gsub(/\^/,"\\^")
doms["(^|[.])"$0"$"]
next
}
{
for (dom in doms) {
if ($0 ~ dom) {
next
}
}
print
}
' fileB fileA
cbbc.co.uk
damazon.co.uk
test.damazon.co.uk
或通过管道:
$ cat fileB | awk '...' - fileA
如果fileB足够小,则不需要数组,您只需构建并测试所有域的1个正则表达式即可:
$ awk '
NR==1 { doms = "(^|[.])(" $0; next }
NR==FNR {
gsub(/[^^]/,"[&]")
gsub(/\^/,"\\^")
doms = doms "|" $0
next
}
FNR==1 { doms = doms ")$" }
$0 !~ doms
' fileB fileA
cbbc.co.uk
damazon.co.uk
test.damazon.co.uk
每个脚本中的两个gsub()
确保将域中的所有正则表达式元字符都视为文字字符。有关其工作原理和方式的详细信息,请参见is-it-possible-to-escape-regex-metacharacters-reliably-with-sed。
答案 1 :(得分:1)
您可以将第一个文件转换为一组要删除的正则表达式:
sed 's/[][\\.^$*+?()]/\\&/g;s/.*/^([^.]+\\.)*&$/' fileB
输出是可以传递给grep -vE
的正则表达式序列:
... | grep -vEf - fileA
grep -Ef
一次可以保留多少内存是有限制的,但是30k表达式可能在现代硬件的限制之内。在最坏的情况下,将fileA
分成两半并运行两次。