我有一个巨大的文件(一万个条目),其中包含域(按随机顺序,但没有重复的域并且具有任意数量的子域),这是一个小例子:
domain.com
domain.net
sub.domain.com
anotherdomain.com
a.b.c.d.e.domain.net
5.4.3.2.1.domain.org
4.3.2.1.domain.org
编辑:正确的工作集可在http://p.ip.fi/WRD-(网页速度慢,用wget p.ip.fi/WRD-即时下载)。
我想“修剪”所有子域,即编写一个新文件,删除任何其他域的所有子域。在该示例中,它应该像这样结束(不关心排序):
domain.com
domain.net
anotherdomain.com
4.3.2.1.domain.org
sub.domain.com
、a.b.c.d.e.domain.net
和5.4.3.2.1.domain.org
被删除(作为domain.com
、domain.net
和的子域4.3.2.1.domain.org
),anotherdomain.com
被保留,因为它只是一个不同的域。
我尝试了不同的方法和一些优化,它们有效,但它们太慢(很多小时),因为文件有一万个条目。要想有用,它必须要快(最多 1 分钟左右)。这是我现在所拥有的:
> $TEMP_BLACKLIST
BL=`cat $BLACKLIST`
for ZONE1 in $BL; do
KEEP=1
# sed -e "1,/^$ZONE1$/d" -> optimization: print $BLACKLIST only *after* the $ZONE1 occourence
# break -> optimization: quit the loop if not present
for ZONE2 in `echo $BL | sed -e "1,/^$ZONE1$/d"`; do
if [[ $ZONE1 == *.$ZONE2 ]] ; then
KEEP=0
break
fi
done
if [ $KEEP = 1 ] ; then
echo $ZONE1 >> $TEMP_BLACKLIST
fi
done
mv $TEMP_BLACKLIST $BLACKLIST
代码应该包含在 bash 脚本内,因此只需 bash,最终调用从中调用的一些常见嵌入式脚本语言(awk、Perl 或其他语言)(无自定义 C 代码)。
您知道更好的方法吗?
答案1
尝试这个,
rev file \
| sort -u \
| tr '.' ',' \
| awk '$0!~dom_regex{print;dom_regex="^"$0"[.]";};NR==1{dom_regex="^"$0"[.]";print};' \
| tr ',' '.' \
| rev
输出:
4.3.2.1.domain.org
domain.com
anotherdomain.com
domain.net
解释:
sort
反转文件并消除重复行。此步骤将把“一种”的域/子域与前面最短的域/子域分组在一起。- 该
awk
部分将查看下一个是否属于同一类型(在变量中保存为正则表达式dom_regex
)。如果没有,它将打印该行并设置新的dom_regex
。否则,该行将被跳过。 - 再次反转文件。
答案2
这是另一个版本
sed 's/^/\./' file |
rev |
LC_ALL=C sort -u |
awk 'p == "" || substr($0,1,length(p)) != p { print $0; p = $0 }' |
rev |
sed 's/^\.//'
输入
domain.com
domain.net
sub.domain.com
anotherdomain.com
a.b.c.d.e.domain.net
5.4.3.2.1.domain.org
4.3.2.1.domain.org
b.c
a-b.c
b.b.c
btcapp.api.btc.com
btc.com
输出
a-b.c
b.c
4.3.2.1.domain.org
btc.com
domain.com
anotherdomain.com
domain.net
尝试使用您推荐的数据集http://p.ip.fi/WRD-,我收集的源文件包含 59683 行,过滤后的列表有 34824 行。我看到有 36 行应用于grep btc.com | wc -l
过滤后的列表。
答案3
如果您只有一个域名扩展,请尝试此操作。
awk -F '.' '!seen[$(NF-1)"."$NF]++' file
domain.com
domain.net
anotherdomain.com