首页 > 解决方案 > 如何在 shell 脚本(sed/awk/etc)中删除多余的 www 子域?

问题描述

我需要删除多余的“www”。在不断增长的庞大域列表中添加前缀。这是示例:

# Type 1
domain1.tld
# Type 2
domain2.tld
www.domain2.tld
# Type 3
www.domain3.tld
sub.domain3.tld
foo.domain3.tld
www.sub.domain3.tld

# Expected
domain1.tld
domain2.tld
www.domain3.tld
sub.domain3.tld
foo.domain3.tld

由于列表已经包含超过 200 万行,因此唯一有效的方法是永远。

cp 1.txt 2.txt
while read line; do
  sed "/www.$line/d" -i 2.txt
done < 1.txt

我正在使用 GNU utils 并且已经使用 sed、awk、comm 无济于事。

如何才能做到这一点?

标签: bashshellawksedzsh

解决方案


#! /bin/bash

awk -F. '{
    if($1 != "www")
    {
        arr[$0]=1
    }
    else
    if(arr[substr($0,5)] == 1)
    {
        next
    }
    print
}' file

看看这个,虽然我不确定如果有 200 万条记录它会如何工作。

更新:

说明:awk表达式.用作字段分隔符,所以假设如果行是www.sub.domain3.tld, $1=www, $2=sub...</p>

www它通过使它们在 array 中索引来标记所有不以开头的行arr。假设线是sub.domain3.tld,它将使其索引arr[sub.domain3.tld]并存储e在其中。现在对于以 开头的每一行www.,它会剥离www.并检查剩余的行是否存储在数组中,如果是,则不打印该行。

更新:

这将产生与提供输入的顺序无关的结果,尽管输出的顺序是混乱的:

#! /bin/bash

awk -F. '{
    if ($1 != "www") {
        domains["www."$0]=0
        domains[$0]=1
    }
    else {
        if (domains[$0] == ""){ domains[$0]=1 }
    }
}
END {
    for (domain in domains) {
        if (domains[domain]) { print domain }
    }
}' file

这应该以正确的顺序产生结果,而与提供输入的顺序无关:

#! /bin/bash

awk -F. '{
    if ($1 != "www") {
        redundant_domains["www."$0]=1
    }
    domains[NR]=$0
}
END {
    for (i=1 ; i < NR ; ++i) {
        if (!redundant_domains[domains[i]]) { print domains[i] }
    }
}' file

推荐阅读