匹配模式并使用awk仅打印非零字段

时间:2015-12-25 17:24:12

标签: regex awk gawk

我有这样的文件,我想搜索模式匹配" / 4126 /"并且仅打印月份和年份以及金额(金额并不总是在2014年1月,如下例所示)。

awk -F! '/4126/ {print $0}'  prints the entire line

但我需要将它打印出来的月份/年份和金额如下:

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公式来做到这一点。提前谢谢。

3 个答案:

答案 0 :(得分:3)

你几乎就在那里,$ 0是整行,你需要一个特定的领域(和标题)

$ awk -F! 'NR==2{h=$3} $2~/\y4126\y/{print h; print $3}' file

Jan 2014 
25492.00 

您的样本输出会打印上一个值,如果它不是拼写错误,您应保留上一行并在匹配后打印。

要消除错误匹配,请将模式保留到相应的字段并使用字边界。

要打印所有非零金额,您可以执行以下操作

$ awk -F! 'NR==2{h[3]=$3; h[4]=$4; h[5]=$5}
   $2~/\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

答案 1 :(得分:1)

非常不清楚您是要求打印某个列的值还是名为“2014年1月”的列的值,或者是所有列的值以及您在其中找到的列中的标题行否则可能这就是你想要的:

$ awk -F' *! *' -v tgt=4123 -v col=3 'NR==2{hdr=$col} $2==tgt{print hdr ORS $col}' file
Jan 2014
4667.00

$ awk -F' *! *' -v tgt=2104 -v col=4 'NR==2{hdr=$col} $2==tgt{print hdr ORS $col}' file
Feb 2014
25198.97

鉴于您的新要求:

$ cat tst.awk
BEGIN { FS=" *! *"; OFS="\t" }
NR==2 { split($0,hdrs) }
$2==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($0,hdrs) }
$2==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

如果您提供了一个可以生成多列输出的示例,您可以保存我们的猜测。

答案 2 :(得分:0)

awk '$4~/Jan/{print $4, $5};$4~/4667.00/{print $4}' file
 Jan 2014
 4667.00

由于我没有定义任何字段分隔符,因此awk使用其内置空间。因此,如果列$ 4匹配Jan打印字段4和5.如果列4匹配4667打印字段4,则再次相同。