Bash
使用腳本(bash、awk 或類似)修剪文件中其他域的子域
我有一個巨大的文件(一萬個條目),包含域(以隨機順序,但沒有重複的域和任意數量的子域),這裡有一個小例子:
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 程式碼)。
你知道更好的方法嗎?
這是另一個版本
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
應用於過濾列表。
試試這個,
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
。如果沒有,它將列印該行並設置 newdom_regex
。否則,將跳過該行。- 再次反轉文件。