1

我知道这对你们中的一位大师来说真的很容易!

我有一个这样的列表:

 www.google.com
 ebay.com
 yahoo.com
 www.bing.com
 www.buy.com
 woot.com
 news.google.com
 images.google.com

我正在尝试编写一个 bash/sed/awk 脚本来清理这个列表。我需要列表看起来像这样:

 www.google.com
 www.ebay.com
 www.yahoo.com
 www.bing.com
 www.buy.com
 www.woot.com
 news.google.com
 images.google.com

总之,它需要添加“www”。如果它还没有 www 或子域。该列表位于名为 theList 的文件中。我的蹩脚尝试是这样的:

 sed 's/^www\./' theList > cleanedList

这显然不适用于已经有 www 或子域的情况。任何想法,将不胜感激。

谢谢!

电动汽车

4

3 回答 3

1

使用 awk 比使用 sed 容易得多。例如:

awk -F. 'NF == 2 {print "www." $0; next}; {print}' theList > cleanedList

这将“子域”定义为名称中少于两个点的任何内容,使用点作为每个记录中的字段分隔符。你当然可以调整它以适应。

它正确处理提供的语料库,如您在此处看到的:

$ cat cleanedList
www.google.com
www.ebay.com
www.yahoo.com
www.bing.com
www.buy.com
www.woot.com
news.google.com
images.google.com
于 2012-06-15T21:32:54.987 回答
1

在 bash 中,你可以这样写:

while read; do
  case "$REPLY" in
  www.*|*.*.*)         # begins with www. or contains at least two dots...
    echo "$REPLY"      # ...leave as-is
    ;;
  *)                   # all other cases...
    echo "www.$REPLY"  # ...prepend "www."
    ;;
  esac
done < theList > cleanedList

外部 while 循环从 stdin 读取(重定向到theList最后一行),一次一行。如果没有其他参数,该行将在 shell 变量中结束$REPLY

case 语句类似于 C 的 switch 语句,但它与通配符模式而不是整数常量进行比较。我们使用它将 ( $REPLY) 行分为两类:一类不需要www.前置,另一类不需要。

第一个模式 ( www.|*.*.*)) 实际上有两种选择:要么匹配行www.*(即以 开头www.),要么匹配*.*.*(即,它包含至少两个点(它们可能是相邻的,但这不是验证模板名称的模式),因为*在 Unix 中也匹配.s)。在这种情况下,我们只是输出我们得到的行。

第二个模式 ( *)) 匹配所有内容,但只有在第一个不匹配时才会选择它。在这些情况下,我们输出"www.$REPLY",即。我们添加www.到刚刚读到的那一行。

它们一起实现了您描述的算法。

于 2012-06-15T21:38:01.820 回答
1

关键在于正则表达式。它捕获所有没有子域的独立域,然后将其替换为www.和自身。

sed -ri 's/^([^.]+\.[^.]+)$/www.\1/' YOUR_FILENAME

或者:

sed -r 's/^([^.]+\.[^.]+)$/www.\1/' YOUR_FILENAME > NEW_FILENAME
于 2012-06-15T21:45:15.203 回答