简体   繁体   English

awk:神秘的双线打印

[英]awk: mysterious double line print

I have a $FILE 我有一个$ FILE

1 textline1
1 textline2
1 textline3
1 textline4

I want to search for textline3 and make sum: 1stcolumn+1 我想搜索textline3并进行求和:1stcolumn + 1

Linenumber is: Linenumber是:

lnr=$(grep -n textline3 $FILE | cut -d : -f1)

But when i use awk: 但是当我使用awk时:

awk -v l="$lnr" 'FNR==l{ sub($1,$1 + 1); print }1' $FILE

I get the erroneous (3rd line is double printed) 我得到了错误(第3行是双重打印)

1 textline1
1 textline2
2 textline3
2 textline3
1 textline4

Reason for double printing is , you are printing inside {} and using 1 as well. 双重打印的原因是,您在{}内打印并使用1。 1 means true and awk's default behaviour is to print. 1表示true,awk的默认行为是打印。

awk -v l="$lnr" 'FNR==l{ sub($1,$1 + 1)}1' $FILE

You can avoid the usage of grep and let awk do the magic. 你可以避免使用grep并让awk做出魔法。

awk '/textline3/{sub($1,$1 + 1)}1' file
1 textline1
1 textline2
2 textline3
1 textline4

In general, you can do a awk '/<pattern>/ { <action> }' file for manipulation. 通常,您可以执行awk '/<pattern>/ { <action> }' file进行操作。

If you just want to increment the first field on the N th line, just say so: 如果你只是想增加 n 线上的第一个字段,只是这么说:

$ awk -v line=3 'FNR==line {$1+=1}1' file  # line is more readable than l
1 textline1
1 textline2
2 textline3
1 textline4

Note the 1 here is triggering awk 's default action, consisting in printing the current line. 注意这里的1是触发awk的默认动作,包括打印当前行。 For every line it will print the initial value but for the line number line it will print the 1 st value with its value +1. 对于每一行,将打印的初始值而对于行号line将打印其值+1的1 的价值。

And that's why you see that line twice in your code: because in the action triggered by FNR==line you are already calling print . 这就是为什么你在代码中看到两行的原因:因为在FNR==line触发的动作中你已经调用了print

Theres a few problems with your script: 你的脚本有一些问题:

  1. The specific bug you are asking about: You're calling print inside the action block and then the 1 at the end of the script is a constant true condition which will cause awk to execute it's default action of printing the record again. 您要问的具体错误:您在操作块内部调用print ,然后脚本末尾的1是一个常量的真实条件,这将导致awk执行它再次打印记录的默认操作。
  2. Never use the letter l (el) as a variable name, it looks far too much like the number 1 (one) and so makes your code harder to read. 永远不要使用字母l (el)作为变量名称,它看起来太像数字1 (一),因此使您的代码更难阅读。
  3. You don't need a function call to change $1 , just do $1++ (assuming textline3 doesn't contain chains of white space that must not be concatenated into one blank char). 你不需要函数调用来改变$1 ,只需要$1++ (假设textline3不包含不能连接成一个空白字符的空格链)。
  4. You don't need to use grep+wc to find lines, just keep it in awk. 您不需要使用grep + wc来查找行,只需将其保存在awk中即可。
  5. In general you should avoid using input data (eg $1 ) as either the search regexp or replacement string fields of any *sub() command as that will fail cryptically given various regexp or backreference metacharacters in the input. 一般情况下,您应该避免使用输入数据(例如$1 )作为任何* sub()命令的搜索regexp或替换字符串字段,因为在输入中给定各种正则表达式或反向引用元字符,这将会加密失败。

So your script should be just: 所以你的脚本应该只是:

$ awk '/textline3/{$1++}1' file
1 textline1
1 textline2
2 textline3
1 textline4

Solution using perl 使用perl解决方案

$ perl -pe 's/^(\d+)(?=\s*textline3)/$1+1/e' $FILE
1 textline1
1 textline2
2 textline3
1 textline4

or 要么

perl -pe 's/^(\d+)/$1+1/e if /textline3/' $FILE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM