在 awk 代码块或函数中允许用 NF 做什么?

Kus*_*nda 8 awk posix

参考:实用程序的 POSIX 标准awk

我真正想念的一件事awk是使用分隔符连接数组的能力,就像joinPerl 中的命令一样,通常用于立即输出。

相反,我最终编写了类似的代码

for (key in array)
    joined_string = (joined_string ==  "" ? array[key] : joined_string "," array[key])

print joined_string
Run Code Online (Sandbox Code Playgroud)

或者

joined_string = array[1]
for (i = 2; i <= length(array); ++i)
    joined_string = joined_string "," array[i];

print joined_string
Run Code Online (Sandbox Code Playgroud)

但是,awk如果我更改当前字段,可能会为我执行此操作:

OFS="," # (would probably do this in BEGIN)

n = 0
for (key in array)
    $(++n) = array[key]

print
Run Code Online (Sandbox Code Playgroud)

我相信这是完全合法的。但是,如果当前输入记录的字段多于array数组的条目(“垃圾”将是来自输入文件的数据),这将在输出中产生垃圾。因此,能够做到这一点会很好

OFS = "," # (would probably do this in BEGIN)

n = 0
for (key in array)
    $(++n) = array[key]

NF = n
print
Run Code Online (Sandbox Code Playgroud)

我在标准中找不到任何文字说NF允许修改,但也没有任何文字说它不允许或它调用未定义的行为。我找到的信息是getline setNF。这并不是说我不允许编写自己的函数或代码块来重置NF,并且它提供了在getline“函数”存在的情况下执行此操作的优先级。

它还声明允许分配给$0并且这会重置NF. 这是否意味着下面的代码会更好?

OFS = "," # (would probably do this in BEGIN)

$0 = ""
n = 0
for (key in array)
    $(++n) = array[key]

print
Run Code Online (Sandbox Code Playgroud)

双重问题:

  1. 是否NF允许设置?
  2. 最后一段代码是将数组与输出分隔符连接起来的正确方法吗?

Ste*_*itt 13

据我所知,没有标准文本记录设置的副作用NF,甚至是否允许设置。Gawk 手册(也发布为Effective awkProgramming),它说它试图记录一般的 Awk而不是(仅)GNU 实现,包括以下内容

NF在 的新值NF和重新计算之后递减会丢弃字段的值$0。(直流)

有警告

注意:某些版本在递减时awk不会重建。$0NF

提到的“(dc)”意味着这是Awk 的一个“黑暗角落”一个文档很差(或根本没有)并且行为可能因一种实现而异的地方。

POSIX 将特殊变量定义为

awk设置的变量

但它没有指定它们是否可以由程序设置(作为一般规则)。一些变量的规范确实提到它们可以被修改(参见ARGC, ARGV),其他的则更改它们的后果是实现定义的(ENVIRON),其他的仍然没有提到任何东西,但“显然”打算由程序(OFS等)。

NF的情况下,实验给出了部分答案:

  • 修改NFGNU Awk 中记录的工作,并且mawk也以相同的方式运行;
  • 变化NF的一个真实的awk中被保留,但不会导致$0重新计算。

所以我会说

  1. NF允许设置,但除了设置值外可能没有任何副作用。
  2. 由于设置$0 由 POSIX 指定的,根据规范,最后一个变体是正确的。(它是否正确的方法是有争议的,因为它输了$0。)

如何在 awk 中将数组转换为字符串中的函数很有趣,但正如定义的那样,它依赖于 GNU Awk 扩展,因此不是这个问题的答案。

(有些令人惊讶的是,可以设置的其他变量包括NRFNR,包括在 TOTA 中。FILENAME但是,不能设置,或者更确切地说,设置它会清除其值。)