使用 awk 匹配模式并仅打印非零字段
Match a pattern and print only non zero field using awk
我有一个这样的文件,我想搜索模式匹配“/4126/”并仅打印月份和年份以及金额(金额并不总是在 2014 年 1 月,如下例所示)。
awk -F! '/4126/ {print [=10=]}' prints the entire line
但我只需要打印 month/year 和金额如下:
Jan 2014
25492.00
此处提供了文件中的示例。
+=====================================================================+
! Code ! Jan 2014 ! Feb 2014 ! Mar 2014! Arrears! T o t a l s !
+=====================================================================+
! 1101 ! 26290.00 ! 26290.00 ! 26290.00! 0.00 ! 3,15,480.00 !
! 1102 ! 480.00 ! 480.00 ! 480.00! 0.00 ! 5,760.00 !
! 2104 ! 24213.09 ! 25198.97 ! 25198.97! 0.00 ! 2,73,205.69 !
! 2107 ! 0.00 ! 0.00 ! 0.00! 0.00 ! 14,991.20 !
! 2113 ! 275.00 ! 275.00 ! 275.00! 0.00 ! 3,300.00 !
! 4114 ! 0.00 ! 0.00 ! 1106.00! 0.00 ! 4,424.00*!
! 4123 ! 4667.00 ! 0.00 ! 0.00! 0.00 ! 4,667.00 !
! 4126 ! 25492.00 ! 0.00 ! 0.00! 0.00 ! 25,492.00*!
请提供执行此操作的 awk 公式。提前致谢。
你就快完成了,$0 是整行,你需要一个特定的字段(和 header)
$ awk -F! 'NR==2{h=} ~/\y4126\y/{print h; print }' file
Jan 2014
25492.00
您的示例输出打印了之前的值,如果不是拼写错误,您应该保留之前的行并在匹配后打印。
要消除错误匹配,请将模式保留到相应的字段并带有单词边界。
要打印所有非零金额,您可以执行以下操作
$ awk -F! 'NR==2{h[3]=; h[4]=; h[5]=}
~/\y2104\y/{for(i=3;i<=5;i++)
if($i!=0)
{header=header OFS h[i];
line=line OFS $i
}
print header;
print line}' file
Jan 2014 Feb 2014 Mar 2014
24213.09 25198.97 25198.97
awk '~/Jan/{print , };~/4667.00/{print }' file
Jan 2014
4667.00
由于我没有定义任何字段分隔符,awk 使用其内置 space。因此,如果第 4 列匹配 Jan 打印字段 4 和 5。如果第 4 列匹配 4667 打印字段 4,则再次相同。
非常不清楚您是要打印特定列的值还是名为 "Jan 2014" 的列的值和/或跨所有列和 header 行的值您在其中找到它的列或其他内容,但也许这就是您想要的:
$ awk -F' *! *' -v tgt=4123 -v col=3 'NR==2{hdr=$col} ==tgt{print hdr ORS $col}' file
Jan 2014
4667.00
$ awk -F' *! *' -v tgt=2104 -v col=4 'NR==2{hdr=$col} ==tgt{print hdr ORS $col}' file
Feb 2014
25198.97
鉴于您的新要求:
$ cat tst.awk
BEGIN { FS=" *! *"; OFS="\t" }
NR==2 { split([=11=],hdrs) }
==tgt {
for (i=3;i<(NF-1);i++) {
if ($i != 0) {
hdr = (hdr ? hdr OFS : "") hdrs[i]
txt = (txt ? txt OFS : "") $i
}
}
}
txt { print hdr ORS txt }
$ awk -v tgt=4126 -f tst.awk file
Jan 2014
25492.00
$ awk -v tgt=2104 -f tst.awk file
Jan 2014 Feb 2014 Mar 2014
24213.09 25198.97 25198.97
以上内容适用于任何 awk,并且仅在找到目标值时才产生输出(即,如果未找到目标值,则不会打印空行或其他任何内容)。
实际上 - 在阅读了您在@karakfa 的回答下的评论后,这可能就是您想要的:
$ cat tst.awk
BEGIN { FS=" *! *"; OFS="\t" }
NR==2 { split([=12=],hdrs) }
==tgt {
for (i=3;i<(NF-1);i++) {
if ($i!=0) {
print hdrs[i] ORS $i
}
}
}
$ awk -v tgt=2104 -f tst.awk file
Jan 2014
24213.09
Feb 2014
25198.97
Mar 2014
25198.97
如果您提供了一个从多列生成输出的示例,您就可以避免我们猜测。
我有一个这样的文件,我想搜索模式匹配“/4126/”并仅打印月份和年份以及金额(金额并不总是在 2014 年 1 月,如下例所示)。
awk -F! '/4126/ {print [=10=]}' prints the entire line
但我只需要打印 month/year 和金额如下:
Jan 2014
25492.00
此处提供了文件中的示例。
+=====================================================================+
! Code ! Jan 2014 ! Feb 2014 ! Mar 2014! Arrears! T o t a l s !
+=====================================================================+
! 1101 ! 26290.00 ! 26290.00 ! 26290.00! 0.00 ! 3,15,480.00 !
! 1102 ! 480.00 ! 480.00 ! 480.00! 0.00 ! 5,760.00 !
! 2104 ! 24213.09 ! 25198.97 ! 25198.97! 0.00 ! 2,73,205.69 !
! 2107 ! 0.00 ! 0.00 ! 0.00! 0.00 ! 14,991.20 !
! 2113 ! 275.00 ! 275.00 ! 275.00! 0.00 ! 3,300.00 !
! 4114 ! 0.00 ! 0.00 ! 1106.00! 0.00 ! 4,424.00*!
! 4123 ! 4667.00 ! 0.00 ! 0.00! 0.00 ! 4,667.00 !
! 4126 ! 25492.00 ! 0.00 ! 0.00! 0.00 ! 25,492.00*!
请提供执行此操作的 awk 公式。提前致谢。
你就快完成了,$0 是整行,你需要一个特定的字段(和 header)
$ awk -F! 'NR==2{h=} ~/\y4126\y/{print h; print }' file
Jan 2014
25492.00
您的示例输出打印了之前的值,如果不是拼写错误,您应该保留之前的行并在匹配后打印。
要消除错误匹配,请将模式保留到相应的字段并带有单词边界。
要打印所有非零金额,您可以执行以下操作
$ awk -F! 'NR==2{h[3]=; h[4]=; h[5]=}
~/\y2104\y/{for(i=3;i<=5;i++)
if($i!=0)
{header=header OFS h[i];
line=line OFS $i
}
print header;
print line}' file
Jan 2014 Feb 2014 Mar 2014
24213.09 25198.97 25198.97
awk '~/Jan/{print , };~/4667.00/{print }' file
Jan 2014
4667.00
由于我没有定义任何字段分隔符,awk 使用其内置 space。因此,如果第 4 列匹配 Jan 打印字段 4 和 5。如果第 4 列匹配 4667 打印字段 4,则再次相同。
非常不清楚您是要打印特定列的值还是名为 "Jan 2014" 的列的值和/或跨所有列和 header 行的值您在其中找到它的列或其他内容,但也许这就是您想要的:
$ awk -F' *! *' -v tgt=4123 -v col=3 'NR==2{hdr=$col} ==tgt{print hdr ORS $col}' file
Jan 2014
4667.00
$ awk -F' *! *' -v tgt=2104 -v col=4 'NR==2{hdr=$col} ==tgt{print hdr ORS $col}' file
Feb 2014
25198.97
鉴于您的新要求:
$ cat tst.awk
BEGIN { FS=" *! *"; OFS="\t" }
NR==2 { split([=11=],hdrs) }
==tgt {
for (i=3;i<(NF-1);i++) {
if ($i != 0) {
hdr = (hdr ? hdr OFS : "") hdrs[i]
txt = (txt ? txt OFS : "") $i
}
}
}
txt { print hdr ORS txt }
$ awk -v tgt=4126 -f tst.awk file
Jan 2014
25492.00
$ awk -v tgt=2104 -f tst.awk file
Jan 2014 Feb 2014 Mar 2014
24213.09 25198.97 25198.97
以上内容适用于任何 awk,并且仅在找到目标值时才产生输出(即,如果未找到目标值,则不会打印空行或其他任何内容)。
实际上 - 在阅读了您在@karakfa 的回答下的评论后,这可能就是您想要的:
$ cat tst.awk
BEGIN { FS=" *! *"; OFS="\t" }
NR==2 { split([=12=],hdrs) }
==tgt {
for (i=3;i<(NF-1);i++) {
if ($i!=0) {
print hdrs[i] ORS $i
}
}
}
$ awk -v tgt=2104 -f tst.awk file
Jan 2014
24213.09
Feb 2014
25198.97
Mar 2014
25198.97
如果您提供了一个从多列生成输出的示例,您就可以避免我们猜测。