![awk:创建新记录并更新 NR](https://linux22.com/image/15108/awk%EF%BC%9A%E5%88%9B%E5%BB%BA%E6%96%B0%E8%AE%B0%E5%BD%95%E5%B9%B6%E6%9B%B4%E6%96%B0%20NR.png)
更多的是一个一般性问题,而不是要解决的具体问题。
假设我有一个像这样的文件
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
。
我将 和 添加NR
到onr
输出中,并将示例输入更改为:
$ cat file
entry 13
entry 15
entry 18
强调一下实际上有 3 个独立的数据项在起作用:
NR
= 输入记录数,onr
= 输出记录数,val
= 每条记录要打印的 $2 的值
为了程序的清晰度、内聚性、耦合性、维护性等,最好不要使它们中的任何一个过载。
答案2
编辑+警告
正如下面的评论中所述,NR
并且FNR
是根据定义计数器输入记录因此应该保持不变。 (参考:呆呆手册)不要按照下面的建议操纵这些值,尽管可以不受限制地这样做!我会留下这个答案作为警告。
好的,感谢 Jeff Schaller、Romeo Ninov 和 fra-san 的评论,以下方法有效:
- 手动增加
NR
或FNR
- 使用正确定义的循环
NR
/FNR
可能的脚本:
awk 'BEGIN {print "NR","line"}
$2 > NR { for (NR; NR<$2; NR++) print NR,"entry "NR }
{print NR,$0}' infile
替换NR
为FNR
以确保在多个输入文件的情况下正确编号(并且可能仍使用NR++
以确保正确的总数)。
由此NR++
模拟更新NR
,而循环模拟在同一记录上重新运行命令(与语句的伪相反next
),这总体上使它就像一个新创建的具有匹配NR
(FNR
)的记录。