【问题标题】:Is there an array version of $1...$NF in awk?awk 中是否有 $1...$NF 的数组版本?
【发布时间】:2015-01-30 10:00:51
【问题描述】:

考虑以下目前处于公共领域的功能。

function join(array, start, end, sep, result, i)
{
    if (sep == "")
       sep = " "
    else if (sep == SUBSEP) # magic value
       sep = ""
    result = array[start]
    for (i = start + 1; i <= end; i++)
        result = result sep array[i]
    return result
}

我想使用此函数连接连续的列,例如$2, $3, $4,其中开始和结束范围是变量。

但是,为了做到这一点,我必须首先使用如下循环将所有字段转换为数组。

for (i = 1; i <= NF; i++) {
    a[i] = $i    
}

或者更短的版本,就像@StevenPenny 提到的那样。

split($0, a)

不幸的是,这两种方法都需要创建一个新变量。

awk 是否有一种将列作为数组访问的内置方式,从而不需要上述手动转换?

【问题讨论】:

  • 你就不能split($0, a)吗?
  • @StevenPenny,当然,我会将其编辑到问题中,但它仍然涉及创建一个新变量。
  • @merlin2011 为什么需要将它们放在一个数组中?它们已经被设置为你可以循环到的变量,并且因为 awk 中的所有变量都是全局的,所以不需要向函数传递任何东西,除非你想要一个函数唯一的数组,在这种情况下你会无论如何都需要创建一个新变量。

标签: arrays awk


【解决方案1】:

没有这样的数组是defined in POSIX awk(唯一的数组类型特殊变量是ARGVENVIRON)。

gawk 中也不存在,尽管它添加了 PROCINFOSYMTABFUNCTAB 特殊数组。您可以在运行时使用SYMTAB 数组(gawk-4.1.0 功能)检查所有定义的变量和类型:

BEGIN { PROCINFO["sorted_in"]="@ind_str_asc" }  # automagic sort for "in"
{ print $0 }
END   { for (ss in SYMTAB) printf("%-12s: %s\n",PROCINFO["identifiers"][ss],ss)  }

(尽管您会发现列表中缺少SYMTABFUNCTAB 本身,并且--dump-variables 中也缺少它们,但它们是经过设计特殊处理的)。 gawk 还提供了一些标准的可加载扩展,但没有一个实现此功能(并且鉴于 $0$1...、NFOFS 之间的动态关系,具有相同功能的数组将是实现起来有点棘手)。

正如 Jidder 所建议的,一种解决方法是完全跳过数组并使用字段。字段名称没有什么特别之处,变量$n 可以与$1 之类的文字一样使用(注意在$(NF-1) 等表达式中使用大括号作为优先级。这是一个fjoin 函数字段而不是数组:

function fjoin(start,end,sep,    result,ii) {
    if (sep=="") sep=" "
    else if (sep==SUBSEP) sep =""
    result=$start
    for (ii=start+1; ii<=end; ii++) 
        result=result sep $ii
    return result
}

{ print "2,4: " fjoin(2,4,":") }

(这不会将$0视为特例)

或者只是使用 split() 并且很高兴,gawk 至少保证它的行为与字段拆分相同(假设 FSFIELDWIDTHS 和可能的 IGNORECASE 都没有被修改以改变行为)。

【讨论】:

    【解决方案2】:

    这是我在自己的代码中所做的

    function iter0gen() { 
       
       PROCINFO["sorted_in"] = "@ind_num_asc"; # skip this for mawk
    
       return split(sprintf("%0"(NF)"d", 0), iter0, //) 
    }
    

    既然用空字符串分割意味着每个bin 1个字符,那么只需分割一个长度等于NF的零字符串,创建一个名为iter0的数组,然后你可以这样做

    for (x in iter0) { $(x) = do stuff….. }
    

    这仅适用于您需要惰性迭代器的情况。这样做的好处是,由于默认情况下索引从 1 开始,因此您不会在迭代器循环中意外获得 $0。这样做的缺点是,如果您不小心,您将在分配到任何字段的那一刻将所有输入 FS 切换到 OFS,这不会代表您预先备份 $0。

    如果您只想要列,那么只需使用FS 执行数组的标准split()。如果您正在使用 gawk 并且也想要 seps 数组,请添加不可移植的可选第四个参数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-06
      • 2014-06-26
      • 2020-08-29
      • 1970-01-01
      • 2019-12-30
      • 2020-10-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多