awk getline()函数无法处理空行

时间:2017-02-14 17:26:05

标签: awk

假设我有一个输入文件,其内容为

cat file


[source,I]

[source,more]

[source,1234]

[source,content]

首先观察两个空行,然后是以[source开头的模式,然后从后续点开始单个空行。我想删除一个或多个空行后跟一个模式(或者删除,删除一个以[source开头的模式上方的一个或多个空行)。我希望输出为

[source,I]    
[source,more]    
[source,1234]    
[source,content]

我制定了Awk逻辑

awk '!NF{getline n; if ( match(n, /^\[source/) )  {print n}}' file

除了它跳过了两个空行之后的模式并产生输出

之外,它完美地工作
[source,more]
[source,1234]
[source,content]

我尝试通过打印getline() Awk应该已完成match()并打印该行的行NR来解决awk '!NF{getline n; if ( match(n, /^\[source/) ) {print n} else {print NR}}' file 2 # Why did this fail for NR==2? [source,more] [source,1234] [source,content] 调用失败的原因,

NR==2

想知道当getline()应该返回[source,I]并且在匹配正则表达式后打印相同内容时,$ awk --version GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4-p1, GNU MP 6.1.1) 失败的原因。

{{1}}

3 个答案:

答案 0 :(得分:3)

如果您预先添加调试打印,您可以看到发生了什么:

$ awk '{print ">", NR, NF, $0} !NF{getline n; if ( match(n, /^\[source/) )  {print n} else {print NR}}' file
> 1 0
2
> 3 1 [source,I]
> 4 0
[source,more]
> 6 0
[source,1234]
> 8 0
[source,content]

所以awk读取为空的第1行,因此!NF为真所以它会读取第2行的getline,它也是空的,它不匹配()而是打印当前的行号,这是2。

现在awk读取第3行[source,I],这是非空的,因此!NF为假,因此不执行动作块,并且只丢弃第3行。

现在awk读取第4行....依此类推。

当然,对于像这样的问题,getline是错误的方法,一旦你修改了你的样本输入/输出,我们就可以向你展示如何以正确的方式做你想做的事情,但是这样的声音你就是这样的真的想做:

$ awk 'NF{if (/^\[source/) print buf $0; buf=""; next} {buf = buf $0 ORS}' file


[source,I]

[source,more]

[source,1234]

[source,content]

答案 1 :(得分:2)

如果getline是强制性的,您可以在do ... while

中使用gawk进行尝试
 awk '!NF{
     do getline n; while(length(n)==0); 
     if ( match(n, /^\[source/) ) print n}' file

你明白了,

[source,I]
[source,more]
[source,1234]
[source,content]

答案 2 :(得分:1)

@Inian:当然它只打印第二行号,因为getline n表示光标从第1行进入下一行,显然当它进入第2行时,如果你打印NR,它将只打印第2行。 所以当光标到达第一行时它会看到!NF然后进入它然后getline确保它应该转到第二行并将它的值存储到n所以第二行也是空的所以它将打印那里的行数。

建议代码恕我直言:

awk '!NF{getline n; if ( match(n, /^\[source/) )  {print n} else {print NR};next} NF'  Input_file

通过对代码进行微小更改,您将能够获得代码中缺少的第3个源代码行。所以在这里你要检查NF是否为NULL,当1为空时它将起作用,接着是下面的源行将工作,即使你有n个空行然后是源行。因此,在NF条件下,在上面和后面添加NF也应该可以解决问题。

如果不需要,您可以删除上面的打印NR。如果我在这里遗漏了一些内容,我很抱歉,请告诉我这是否有帮助。

编辑:当Inian问为什么它在第二行失败时,让我试一试,如果我正确理解问题并且可以在这里解释。

awk '!NF                       ###### !NF, checking that if any line is empty or not, if it is empty then do following.
{getline n;                    ###### getline n, means go to next line(which will be 2nd line now) and have it's value into variable named n.
if ( match(n, /^\[source/) )   ###### if n matches the regex pattern then do following, NOTE as n is EMPTY in case of 2nd line is empty,
                                      so it will NOT pass the if condition it will go to else and print the line number which is 2.
{print n} else {print NR}}'    ###### printing n in case if condition is TRUE. using else if above condition is NOT true.