从文件中过滤黑名单域

filter blacklist domains from file

我有两个文件

第一个文件 blacklist.txt 包含

test.example.com
*.test.example.com

第二个文件subdomains.txt包含

test.example.com
123.test.example.com
abc-test.example.com
www.example.com

预期结果文件包含

abc-test.example.com
www.example.com

这是从 subdomains.txt 中过滤黑名单文件中列出的所有子域 如果存在 *.,它会同时检查正则表达式,然后也会删除所有子域,如预期结果所示。

在我的搜索过程中,我发现以下命令使用 awk 但如果文件 blacklist.txt 中有 * 则不起作用 awk 'NR == FNR { list[tolower([=15=])]=1; next } { if (! list[tolower([=15=])]) print }' blacklist.txt subdomains.txt

但是当它只包含域时它会过滤掉

我也尝试过 comm 命令,但它似乎无法处理正则表达式

如果稍微修改一下黑名单正则表达式:

test\.example\.com
.*\.test\.example\.com

你可以:

$ awk 'NR==FNR {
    a[[=11=]];next
}
{
    for(i in a)
        if(match([=11=],"^" i "$"))
            next
    print
}' blacklist subdomains

输出:

abc-test.example.com
www.example.com

如果您使用 sed 处理黑名单以将其转换为正则表达式列表,您可以使用:

sed 's/\./\./g;s/\*/.*/g' blacklist.txt |
grep -vixf - subdomains.txt

不需要对黑名单模式进行任何预处理的纯bash版本:

#!/usr/bin/env bash

readarray -t blacklist < blacklist.txt
while read -r domain; do
    match=0
    for pat in "${blacklist[@]}"; do
        if [[ $domain == $pat ]]; then
            match=1
            break
        fi
    done
    [[ $match -eq 0 ]] && printf "%s\n" "$domain"
done < subdomains.txt

并且把它放进去,一个 tcl 版本应该比上面的脚本在大文件上更有效:

#!/usr/bin/env tclsh

# Takes two arguments; the blacklist file and the domain file
# e.g.,
# ./domainfilter blacklist.txt subdomains.txt > results.txt

proc ggrep {blacklist domainfile} {
    set f [open $domainfile]
    set domains [split [read -nonewline $f] \n]
    close $f
    set f [open $blacklist]
    while {[gets $f pattern] >= 0} {
        set domains [lsearch -inline -all -not -glob $domains $pattern]
    }
    close $f
    puts [join $domains \n]
}
ggrep [lindex $argv 0] [lindex $argv 1]

也是一个更高效的 zsh 版本,如果 shell 是一个选项:

#!/usr/bin/env zsh

declare -A blacklist
while read -r pattern; do
    blacklist[$pattern]=1
done < blacklist.txt

while read -r domain; do
    # Treat the array keys as glob patterns matched against index
    [[ -z ${blacklist[(k)$domain]} ]] && printf "%s\n" "$domain"
done < subdomains.txt