Bash 适用于awk v4.0.2但不适用于>;=4.2.1

Bash 适用于awk v4.0.2但不适用于>;=4.2.1,bash,ubuntu,awk,centos7,alpine,Bash,Ubuntu,Awk,Centos7,Alpine,我有这个awk命令: echo www.host.com |awk -F. '{$1="";OFS="." ; print $0}' | 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版本中工作?对于您提供的示例,请尝试以下内容。这将尝试从第一个

我有这个awk命令:

echo www.host.com |awk -F. '{$1="";OFS="." ; print $0}' | 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($0,/\..*/){print substr($0,RSTART+1,RLENGTH-1)}'


OP的代码修复:如果OP想要使用他/她自己尝试过的代码,那么下面可能会有所帮助。这里有两点:1-我们不需要使用任何其他命令以及
awk
来进行处理。第二-我们需要在每个行中执行的
BEGIN
部分中设置
FS
OFS
的值

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

对于您提供的样品,请尝试以下内容。这将尝试从第一个
到最后一行匹配正则表达式,然后从第一个点到最后一行打印

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


OP的代码修复:如果OP想要使用他/她自己尝试过的代码,那么下面可能会有所帮助。这里有两点:1-我们不需要使用任何其他命令以及
awk
来进行处理。第二-我们需要在每个行中执行的
BEGIN
部分中设置
FS
OFS
的值

echo www.host.com | awk 'BEGIN{FS=OFS="."} {$1="";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
}'
如果您有任意长的FQDN,它也可以工作:

$ 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["co\034uk"]
}
{
    print (($(NF-1),$NF) in pecs?$(NF-2) OFS:"")$(NF-1),$NF
}'
like.co.uk

要获取域,请使用:

$ 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
}'
如果您有任意长的FQDN,它也可以工作:

$ 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["co\034uk"]
}
{
    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-

使用的选项包括:

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

关于awk,您得到了两个非常好的答案,但我认为这应该通过
cut
来处理,因为它提供了从已知位置开始的所有字段的简单性:

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

使用的选项包括:

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

您观察到的是GNU awk中的一个bug,该bug在4.2.1版中修复。changlog说:

2014-08-12阿诺德·罗宾斯

如果需要重新设置
$0
,则正在设置的OFS应使用以前的
OFS
重新生成
$0
重建。感谢迈克·布伦南指出这一点

  • awk.h(
    重建记录
    ):声明
  • eval.c(
    set\u of s
    ):如果没有从
    var\u init()
    调用,请检查
    $0
    是否需要重建。如果是这样,请完全解析记录并重建它。使
    OFS
    下次指向新的
    OFS
    的单独副本,因为
    OFS\u节点->var\u值->stptr
    是 现在已经更新了

  • field.c(
    rebuild\u record
    ):现在是外部的,而不是静态的。使用OFS的
    OFS
    和OFSlen的
    OFS
    而不是OFS\u节点的

在OP中读取代码时,它会声明:

awk -F. '{$1="";OFS="." ; print $0}'
根据POSIX的规定,其功能如下:

  • -F.
    设置字段分隔符
    FS
    以表示-字符
  • 读唱片
  • 使用
    FS=“.”
  • $1=”“
    使用OFS
    重新定义字段1并重建记录
    $0
    。此时,
    OFS
    被设置为单个空间。如果记录
    $0
    www.foo.com
    ,则它现在将读取
    \u foo\u com
    (下划线表示空格)。重新计算现在只有一个的字段数,因为不再有可用的
    FS
  • OFS=“.”
    将输出字段分隔符
    OFS
    重新定义为-字符。这就是bug发生的地方。Gnu awk知道需要进行重建,但已经用新的OFS而不是旧的OFS进行了重建
  • **
    打印$0':**打印记录$0,该记录现在是
    \u foo\u com`
  • 对程序的最小更改是:

    awk -F. '{OFS="."; $1=""; print $0}'
    
    awk 'BEGIN{FS=OFS="."}{$1="";print $0}'
    
    彻底的改变是:

    awk -F. '{OFS="."; $1=""; print $0}'
    
    awk 'BEGIN{FS=OFS="."}{$1="";print $0}'
    
    最完美的改变是将
    awk
    sed
    替换为

    如果其中有一个具有该名称的变量,则可以使用:

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

    您所看到的是GNU awk中的一个bug,它在4.2.1版中得到了修复。changlog说:

    2014-08-12阿诺德·罗宾斯

    如果需要重新设置
    $0
    ,则正在设置的OFS应使用以前的
    OFS
    重新生成
    $0
    重建。感谢迈克·布伦南指出这一点

    • awk.h(
      重建记录
      ):声明
    • eval.c(
      set\u of s
      ):如果没有从
      var\u init()
      调用,请检查
      $0
      是否需要重建。如果是这样,请完全解析记录并重建它。使
      OFS
      下次指向新的
      OFS
      的单独副本,因为
      OFS\u节点->var\u值->stptr
      是 现在已经更新了