适用于 awk v4.0.2 但不适用于 >= 4.2.1 的 awk 表达式

awk expression that works on awk v4.0.2 but it does not on >= 4.2.1

我有这个 awk 命令:

echo www.host.com |awk -F. '{="";OFS="." ; print [=10=]}' | sed 's/^.//'

它的作用是从主机名中获取域:

host.com

该命令适用于 CentOS 7 (awk v 4.0.2),但不适用于 ubuntu 19.04 (awk 4.2.1) 或 alpine (gawk 5.0.1),输出为:

host com

我怎样才能修复那个 awk 表达式,使其在最近的 awk 版本中工作?

对于您提供的示例,请尝试以下操作。这将尝试从第一个 . 到行的最后匹配正则表达式,然后在第一个点之后打印到行的最后。

echo www.host.com | awk 'match([=10=],/\..*/){print substr([=10=],RSTART+1,RLENGTH-1)}'


OP 的代码修复: 如果 OP 想要使用 his/her 自己尝试过的代码,那么以下内容可能会有所帮助。这里有两点: 1st- 我们不需要使用任何其他命令和 awk 来处理。第二-我们需要在 BEGIN 部分中设置 FSOFS 的值,您在每一行中都在做。

echo www.host.com | awk 'BEGIN{FS=OFS="."} {="";sub(/\./,"");print}'

要获取域,请使用:

$ echo www.host.com | awk 'BEGIN{FS=OFS="."}{print $(NF-1),$NF}'
host.com

解释:

awk '
BEGIN {                 # before processing the data
    FS=OFS="."          # set input and output delimiters to .
}
{
    print $(NF-1),$NF   # then print the next-to-last and last fields
}'

如果您有任意长的 fqdns,它也可以工作:

$ echo if.you.have.arbitrarily.long.fqdns.example.com |
awk 'BEGIN{FS=OFS="."}{print $(NF-1),$NF}'
example.com

是的,有趣的是,您的版本确实适用于 4.0.2。和 awk 版本 20121220.

更新:

更新了一些内容检查功能,请参阅评论。是否有高于三级的域名?:

$ echo and.with.peculiar.fqdns.like.co.uk | 
awk '
BEGIN {
    FS=OFS="."
    pecs["co4uk"]
}
{
    print (($(NF-1),$NF) in pecs?$(NF-2) OFS:"")$(NF-1),$NF
}'
like.co.uk

你在 awk 上得到了 2 个非常好的答案,但我认为这应该用 cut 来处理,因为它提供了让所有字段从已知位置开始的简单性:

echo 'www.host.com' | cut -d. -f2-

host.com

使用的选项是:

  • -d.: 设置分隔符为.
  • -f2-:提取从位置2开始的所有字段

您观察到的是 GNU awk 中的一个错误,该错误已在 4.2.1 版中修复。变更日志指出:

2014-08-12 Arnold D. Robbins

OFS being set should rebuild [=14=] using previous OFS if [=14=] needs to be rebuilt. Thanks to Mike Brennan for pointing this out.

  • awk.h (rebuild_record): Declare.
  • eval.c (set_OFS): If not being called from var_init(), check if [=14=] needs rebuilding. If so, parse the record fully and rebuild it. Make OFS point to a separate copy of the new OFS for next time, since OFS_node->var_value->stptr was already updated at this point.

  • field.c (rebuild_record): Is now extern instead of static. Use OFS and OFSlen instead of the value of OFS_node.

阅读 OP 中的代码时,它指出:

awk -F. '{="";OFS="." ; print [=10=]}'

根据 POSIX,它执行以下操作:

  1. -F.: 设置字段分隔符 FS 来表示 -character
  2. 读取一条记录
  3. 使用FS="."
  4. 进行字段拆分
  5. ="": 重新定义字段 1 并使用 OFS 重建记录 [=14=]。此时OFS设置为单个space。如果记录 [=14=]www.foo.com,它现在显示为 _foo_com(下划线代表 spaces)。重新计算现在只有一个字段的数量,因为不再有 FS 可用。
  6. OFS=".": 将输出字段分隔符 OFS 重新定义为 字符。这就是错误发生的地方。 Gnu awk 知道需要进行重建,但是已经使用新的 OFS 而不是旧的 OFS.
  7. **print [=43=]':** print the record [=43=] which is now_foo_com`.

对您的程序的最小更改是:

awk -F. '{OFS="."; =""; print [=11=]}'

彻底的改变是:

awk 'BEGIN{FS=OFS="."}{="";print [=12=]}'

完美的更改是用

替换 awksed

如果你有一个同名的变量,你可以使用:

var=www.foo.com
echo ${var#*.}