【问题标题】:Can I pass an array to awk using -v?我可以使用 -v 将数组传递给 awk 吗?
【发布时间】:2016-01-11 09:20:29
【问题描述】:

我希望能够将数组变量传递给awk。我不是指一个 shell 数组,而是一个原生的 awk 数组。我知道我可以像这样传递标量变量:

awk -vfoo="1" 'NR==foo' file

我可以使用相同的机制来定义awk 数组吗?比如:

$  awk -v"foo[0]=1" 'NR==foo' file
awk: fatal: `foo[0]' is not a legal variable name

我已经尝试了上面的一些变体,但它们都不能在我的 Debian 上的 GNU awk 4.1.1 上运行。那么,是否有任何版本的awkgawkmawk 或其他任何版本)可以接受来自-v 开关的数组?

我知道我可以解决这个问题并且可以很容易地想到解决方法,我只是想知道是否有任何 awk 实现本身支持这种功能。

【问题讨论】:

  • 我不确定答案,但我怀疑不是,据我所知,awk 甚至不支持像 a = [1, 2, 3] 这样的数组初始化...
  • 我认为这是不可能的。请注意@TomFenech,这种初始化是不可能的,因为在awk 中它们只是关联的。
  • 您不能在 awk 之外定义它,但您可以通过序列化将 bash 数组转换为 awk 数组,请参阅stackoverflow.com/a/32887826/1435869
  • @karakfa 谢谢,但我知道这一点。这就是为什么我特别指出“我的意思不是一个shell数组,而是一个原生的awk一个”。

标签: arrays awk gawk mawk


【解决方案1】:

您可以使用 mawk 或 gawk 中的 split() 函数来拆分“-v”值的输入(这里是 gawk 手册页):

split(s, a [, r [, seps] ])

将字符串 s 拆分为数组 a 和分隔符数组 seps on 正则表达式 r,并返回字段数。*

这里的一个例子,我将值“ARRAYVAR”,一个逗号分隔的值列表,这是我的数组,用“-v”传递给 awk 程序,然后使用split() 函数,然后打印数组的第三个值:

echo 0 | gawk -v ARRAYVAR="a,b,c,d,e,f" '{ split(ARRAYVAR,arrayval,","); print(arrayval[3]) }'
c

似乎工作:)

【讨论】:

  • 是的,谢谢,我知道了。这就是为什么我特别说“我的意思不是 shell 数组,而是原生 awk 数组”。问题是关于使用-v 开关传递awk 数组,而不是在脚本中生成数组。
  • 请注意,您可以通过说awk 'BEGIN {actions here} 来测试您的awk。无需echo ... | awk
【解决方案2】:

根据定义,这似乎是不可能的。

man awk 我们得到了:

-v var=val

--赋值 var=val

在执行之前将值 val 赋给变量 var 程序开始。此类变量值可用于 BEGIN 规则 AWK 程序。

然后我们在Using Variables in a Program 中读到:

变量的名称必须是字母、数字或 下划线,并且不能以数字开头。

awk 中的变量可以分配数值或字符串值。

因此,-v 实现的定义方式使得将数组作为变量提供是不可能的,因为=[ 字符的任何类型的使用都不允许作为-v 变量的一部分通过。两者都是必需的,因为 awk 中的数组只是关联的。

【讨论】:

    【解决方案3】:

    很遗憾,这是不可能的。但是,您可以使用一些巧妙的方法将 bash 数组转换为 awk 数组。

    我最近想通过将 bash 数组传递给 awk 来使用它进行过滤来做到这一点,所以这就是我所做的:

    $ arr=( hello world this is bash array )
    $ echo -e 'this\nmight\nnot\nshow\nup' | awk 'BEGIN {
      for (i = 1; i < ARGC; i++) {
          my_filter[ARGV[i]]=1
          ARGV[i]="" # unset ARGV[i] otherwise awk might try to read it as a file
      }
    } !my_filter[$0]' "${arr[@]}"
    

    输出:

    might
    not
    show
    up
    

    【讨论】:

    • 是的,谢谢,我知道了。这就是为什么我特别说“我的意思不是 shell 数组,而是原生 awk 数组”。问题是关于使用 -v 开关传递 awk 数组,而不是在脚本中生成数组
    【解决方案4】:

    对于关联数组,您可以将其作为键值对字符串传递,然后在 BEGIN 部​​分重新格式化。

    $ echo | awk -v m="a,b;c,d" '
    BEGIN {
      split(m,M,";")
      for (i in M) {
        split(M[i],MM,",")
        MA[MM[1]]=MM[2]
      }
    }
    {
      for (a in MA) {
        printf("MA[%s]=%s\n",a, MA[a])
      }
    }'
    

    输出:

    MA[a]=b
    MA[c]=d
    

    【讨论】:

    • 谢谢,但正如我在问题中所说,我知道如何解决这个问题。问题是专门询问数组是否可以作为变量传递。 awk 是一种成熟的编程语言,因此您当然可以按照此处描述的方式进行操作。
    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多