awk:创建新记录并更新 NR

awk:创建新记录并更新 NR

更多的是一个一般性问题,而不是要解决的具体问题。

假设我有一个像这样的文件

entry 1
entry 3
entry 6

我想通过 填写缺失的条目awk。能否插入一条新记录并更新 NR?想法是:

awk 'BEGIN {print "NR","line"
     $2!=NR {<create record> "entry",NR ; <repeat commands on same record>}
     {print NR,$0}' file

所以命令会:

  • 插入一条新记录
  • 为新记录提供匹配的 NR 并更新以下记录编号
  • 有能力重新检查条件(即:当entry 6达到时,它应该创建entry 4但意识到entry 5也丢失了。因此它应该重新检查记录的条件entry 6

所需输出

NR line
1  entry 1
2  entry 2
3  entry 3
4  entry 4
5  entry 5
6  entry 6

答案1

不能在输入文件的一次传递中创建一个新的输入记录。创建新的输入记录意味着此代码:

awk '
    {
        print $0
        magic to create a new record with contents "Foo"
    }
'

会打印原始记录,然后进入无限循环打印“Foo”,因为根据定义 awk 对每个输入记录执行一次上述代码。

您可以对字符串执行代码,无论它们是来自输入记录还是内部创建的,例如:

awk '
    {
        prt($0)
        other stuff
        prt("Foo")
    }
    function prt(str) {
        print str
    }
'

但这与实际创建新的输入记录不同。

您还可以采用两遍方法在第一遍上创建并写入临时文件,以便在第二遍读取临时文件时,新打印的字符串现在作为输入记录出现。

你超载/滥用了NR“虽然”的含义。NR是计数输入已读取的记录,您正在尝试打印计数输出打印的记录是完全不同的事情。没有内置变量,因为只需在单独的变量中自己跟踪它而不是弄乱NR,例如onr下面的内容,这很简单:

$ cat file
awk '
    BEGIN { print "NR", "onr", "line" }
    NR == 1 { val = $2-1 }
    {
        for (val++; val<$2; val++) {
            processString($1 FS val)
        }
        processString($0)
    }

    function processString(str) {
        print NR, ++onr, str
    }
' file
NR onr line
1 1 entry 13
2 2 entry 14
2 3 entry 15
3 4 entry 16
3 5 entry 17
3 6 entry 18

不过,我们并没有创建新的输入记录,所以(一如既往)尝试调整内置变量的值是完全不合适的NR。相反,我们只是生成新的输出记录并在名为 的用户定义变量中跟踪输出记录的总数onr

我将 和 添加NRonr输出中,并将示例输入更改为:

$ cat file
entry 13
entry 15
entry 18

强调一下实际上有 3 个独立的数据项在起作用:

  1. NR= 输入记录数,
  2. onr= 输出记录数,
  3. val= 每条记录要打印的 $2 的值

为了程序的清晰度、内聚性、耦合性、维护性等,最好不要使它们中的任何一个过载。

答案2

编辑+警告

正如下面的评论中所述,NR并且FNR根据定义计数器输入记录因此应该保持不变。 (参考:呆呆手册)不要按照下面的建议操纵这些值,尽管可以不受限制地这样做!我会留下这个答案作为警告。


好的,感谢 Jeff Schaller、Romeo Ninov 和 fra-san 的评论,以下方法有效:

  • 手动增加NRFNR
  • 使用正确定义的循环NR/FNR

可能的脚本:

awk 'BEGIN {print "NR","line"}
     $2 > NR { for (NR; NR<$2; NR++) print NR,"entry "NR }
     {print NR,$0}' infile

替换NRFNR以确保在多个输入文件的情况下正确编号(并且可能仍使用NR++以确保正确的总数)。

由此NR++模拟更新NR,而循环模拟在同一记录上重新运行命令(与语句的伪相反next),这总体上使它就像一个新创建的具有匹配NRFNR)的记录。

相关内容