适用于 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
部分中设置 FS
和 OFS
的值,您在每一行中都在做。
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,它执行以下操作:
-F.
: 设置字段分隔符 FS
来表示 -character
- 读取一条记录
- 使用
FS="."
进行字段拆分
=""
: 重新定义字段 1 并使用 OFS
重建记录 [=14=]
。此时OFS
设置为单个space。如果记录 [=14=]
是 www.foo.com
,它现在显示为 _foo_com
(下划线代表 spaces)。重新计算现在只有一个字段的数量,因为不再有 FS
可用。
OFS="."
: 将输出字段分隔符 OFS
重新定义为 字符。这就是错误发生的地方。 Gnu awk 知道需要进行重建,但是已经使用新的 OFS
而不是旧的 OFS
.
- **
print [=43=]':** print the record [=43=] which is now
_foo_com`.
对您的程序的最小更改是:
awk -F. '{OFS="."; =""; print [=11=]}'
彻底的改变是:
awk 'BEGIN{FS=OFS="."}{="";print [=12=]}'
完美的更改是用
替换 awk
和 sed
如果你有一个同名的变量,你可以使用:
var=www.foo.com
echo ${var#*.}
我有这个 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
部分中设置 FS
和 OFS
的值,您在每一行中都在做。
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 previousOFS
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 fromvar_init()
, check if[=14=]
needs rebuilding. If so, parse the record fully and rebuild it. MakeOFS
point to a separate copy of the newOFS
for next time, sinceOFS_node->var_value->stptr
was already updated at this point.field.c (
rebuild_record
): Is now extern instead of static. UseOFS
andOFSlen
instead of the value ofOFS_node
.
阅读 OP 中的代码时,它指出:
awk -F. '{="";OFS="." ; print [=10=]}'
根据 POSIX,它执行以下操作:
-F.
: 设置字段分隔符FS
来表示-character - 读取一条记录
- 使用
FS="."
进行字段拆分
=""
: 重新定义字段 1 并使用OFS
重建记录[=14=]
。此时OFS
设置为单个space。如果记录[=14=]
是www.foo.com
,它现在显示为_foo_com
(下划线代表 spaces)。重新计算现在只有一个字段的数量,因为不再有FS
可用。OFS="."
: 将输出字段分隔符OFS
重新定义为字符。这就是错误发生的地方。 Gnu awk 知道需要进行重建,但是已经使用新的 OFS
而不是旧的OFS
.- **
print [=43=]':** print the record [=43=] which is now
_foo_com`.
对您的程序的最小更改是:
awk -F. '{OFS="."; =""; print [=11=]}'
彻底的改变是:
awk 'BEGIN{FS=OFS="."}{="";print [=12=]}'
完美的更改是用
awk
和 sed
如果你有一个同名的变量,你可以使用:
var=www.foo.com
echo ${var#*.}