在awk中是否有$ 1 ... $ NF的数组版本?

时间:2014-12-02 08:11:45

标签: arrays awk

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

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是否有以数组形式访问列的内置方式,以便上述手动转换不是必需的?

2 个答案:

答案 0 :(得分:0)

没有这样的数组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也缺少$0$1,但它们会受到设计的特殊处理。 gawk还提供了一些标准的可加载扩展,但是没有实现此功能(并且考虑到NFOFS ...,$n$1之间的动态关系,具有相同功能的数组实现起来有点棘手。)

正如Jidder所建议的,一个解决方法是完全跳过数组并使用字段。字段名称没有什么特别之处,变量$(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,":") } 这样的表达式中使用大括号作为优先级。这是一个{ {1}}函数适用于字段而不是数组:

$0

(这不会将split()视为特殊情况)

或者只是使用FS并且开心,gawk至少保证它的行为与字段拆分相同(假设FIELDWIDTHSIGNORECASE和{{1}}都不是被修改以改变行为。)

答案 1 :(得分:0)

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

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。

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