如何在awk中编写循环而不相互影响?

如何在awk中编写循环而不相互影响?,awk,Awk,我的脚本输出一个包含价格(col$3)的杂货清单(col$1) 然后按类别(第2列)将它们合并,并添加每个类别的成本 问题是,当我运行for循环时,它总是只会弄乱原始杂货清单输出的第一行。 我试着用不同的开头和结尾来分开它们,但没有用 这是我当前的代码,带有子类别的循环被注释掉了 #!/bin/awk BEGIN { FS="\t+"; OFS=" "; printf("%-30s %s\n", "Item","Cost") printf("%-30s %s\n", "====

我的脚本输出一个包含价格(col$3)的杂货清单(col$1) 然后按类别(第2列)将它们合并,并添加每个类别的成本

问题是,当我运行for循环时,它总是只会弄乱原始杂货清单输出的第一行。 我试着用不同的开头和结尾来分开它们,但没有用

这是我当前的代码,带有子类别的循环被注释掉了

    #!/bin/awk
    BEGIN { FS="\t+"; OFS=" "; printf("%-30s %s\n", "Item","Cost") 
printf("%-30s %s\n", "====","====")}
{ printf("%-30s %s\n", $2, $3, 30) }


END {
}

#BEGIN {
#}

#NR==1{print;next}
#{a[$1]+=substr($3, 2)}


#END { for(i in a)printf("%-30s %s\n", i, a[i], 30)  
#}
输出样本:

Item                          Cost
====                          ======
Air freshener                 $10.60
Antiperspirant / Deodorant    $03.80
Apples                        $10.80
Asparagus                     $01.05
Avocados                      $08.25
BBQ sauce                     $08.55
Baby food                     $08.60
Baby wash                     $05.40

Subtotal by Category       
---------------------------
Alcohol             $ 76.10
Baby/Pet            $ 81.55
Baking              $ 54.15
Bread               $ 50.20
Canned goods        $ 55.60
Chips/Crackers      $ 53.65
Cleaner/Detergent   $ 46.75
Condiments          $ 92.40
Dairy               $ 46.30
Produce             $195.45
Soap/Sundry         $113.65
Spices              $ 89.40
===========================
Total               $955.20
输入样本:

Cleaner/Detergent   Air freshener   $10.60
Soap/Sundry Antiperspirant / Deodorant  $03.80
Produce Apples  $10.80
Produce Asparagus   $01.05
Produce Avocados    $08.25
Condiments  BBQ sauce   $08.55
Baby/Pet    Baby food   $08.60
Baby/Pet    Baby wash   $05.40
Bread   Bagels / Croissants $10.35
Baking  Baking powder / Soda    $07.85
Produce Bananas $02.90
Spices  Basil   $01.70
Soap/Sundry Bath soap / Hand soap   $06.75
Cleaner/Detergent   Bathroom cleaner    $04.55

GNUawk解决方案,一次即可满足您的需求:

$ cat tst.awk
#!/bin/awk
BEGIN {
    FS="\t+";OFS="   "
}
NF==3{                                               # check if there are fields
    amount=substr($3,2)
    l1=length($1); l2=length($2)                     # save max length of 1st col
    col1=(l1<l2)?(col1<l2?l2:col1):(col1<l1?l1:col1) # in col1     

    a[$2]=($2 in a? a[$2]+amount : amount)           # item as key, amount as value
    total=total+amount                               # save total, for col2 width
    c[$1]=c[$1]+amount                               # save sum per category
}
END {
    col2=length(total)                               # determine col2 width

    printf "%-*s%s%s\n", col1, "Item", OFS, "Cost"   # print header item table
    printf "%s%s%s\n", separator("=",col1), OFS, separator("=",col2+2) 

    PROCINFO["sorted_in"]="@ind_str_asc"             # define sorting order

    for(i in a)                                      # print Item table
        printf "%-*s%s$ %*.2f\n", col1, i, OFS, col2, a[i]    

    printf "\n%s\n", "Subtotal by Category"          # print header category table
    print separator("-", col1+col2+length(OFS)+2)    # "+2" because of "$ "

    for (j in c)                                     # print category table
        printf "%-*s%s$ %*.2f\n", col1, j, OFS, col2, c[j]    

    print separator("=", col1+col2+length(OFS)+2)    # "+2" because of "$ "
    printf "%-*s%s$ %*.2f\n", col1, "Total", OFS, col2, total # print total
}
func separator(sep,n){                               # function for generating
    s=sprintf("%*s",n,""); gsub(/ /,sep,s); return s # separator line
}

GNUawk解决方案,一次即可满足您的需求:

$ cat tst.awk
#!/bin/awk
BEGIN {
    FS="\t+";OFS="   "
}
NF==3{                                               # check if there are fields
    amount=substr($3,2)
    l1=length($1); l2=length($2)                     # save max length of 1st col
    col1=(l1<l2)?(col1<l2?l2:col1):(col1<l1?l1:col1) # in col1     

    a[$2]=($2 in a? a[$2]+amount : amount)           # item as key, amount as value
    total=total+amount                               # save total, for col2 width
    c[$1]=c[$1]+amount                               # save sum per category
}
END {
    col2=length(total)                               # determine col2 width

    printf "%-*s%s%s\n", col1, "Item", OFS, "Cost"   # print header item table
    printf "%s%s%s\n", separator("=",col1), OFS, separator("=",col2+2) 

    PROCINFO["sorted_in"]="@ind_str_asc"             # define sorting order

    for(i in a)                                      # print Item table
        printf "%-*s%s$ %*.2f\n", col1, i, OFS, col2, a[i]    

    printf "\n%s\n", "Subtotal by Category"          # print header category table
    print separator("-", col1+col2+length(OFS)+2)    # "+2" because of "$ "

    for (j in c)                                     # print category table
        printf "%-*s%s$ %*.2f\n", col1, j, OFS, col2, c[j]    

    print separator("=", col1+col2+length(OFS)+2)    # "+2" because of "$ "
    printf "%-*s%s$ %*.2f\n", col1, "Total", OFS, col2, total # print total
}
func separator(sep,n){                               # function for generating
    s=sprintf("%*s",n,""); gsub(/ /,sep,s); return s # separator line
}

我强烈建议您首先获取数据(对gensub()和\S/\S使用GNU awk-对其他awk使用变量+[g]sub()++[:space:]):

然后,您可以将其读入电子表格和/或编写您希望提供布局的任何格式脚本,例如:

$ awk -f tst.awk file |
  awk 'BEGIN{FS=OFS="\t"} $1!=p{print "_" ORS $1, "Cost" ORS "====", "===="; p=$1} {print $2, "$"$3}' |
  column -s$'\t' -t
_
Item                        Cost
====                        ====
Air freshener               $10.60
Antiperspirant / Deodorant  $03.80
Apples                      $10.80
Asparagus                   $01.05
Avocados                    $08.25
BBQ sauce                   $08.55
Baby food                   $08.60
Baby wash                   $05.40
Bagels / Croissants         $10.35
Baking powder / Soda        $07.85
Bananas                     $02.90
Basil                       $01.70
Bath soap / Hand soap       $06.75
Bathroom cleaner            $04.55
_
Category                    Cost
====                        ====
Spices                      $1.7
Baby/Pet                    $14
Condiments                  $8.55
Produce                     $23
Soap/Sundry                 $10.55
Baking                      $7.85
Bread                       $10.35
Cleaner/Detergent           $15.15
_
Total                       Cost
====                        ====
Total                       $91.15

我强烈建议您首先获取数据(对gensub()和\S/\S使用GNU awk-对其他awk使用变量+[g]sub()++[:space:]):

然后,您可以将其读入电子表格和/或编写您希望提供布局的任何格式脚本,例如:

$ awk -f tst.awk file |
  awk 'BEGIN{FS=OFS="\t"} $1!=p{print "_" ORS $1, "Cost" ORS "====", "===="; p=$1} {print $2, "$"$3}' |
  column -s$'\t' -t
_
Item                        Cost
====                        ====
Air freshener               $10.60
Antiperspirant / Deodorant  $03.80
Apples                      $10.80
Asparagus                   $01.05
Avocados                    $08.25
BBQ sauce                   $08.55
Baby food                   $08.60
Baby wash                   $05.40
Bagels / Croissants         $10.35
Baking powder / Soda        $07.85
Bananas                     $02.90
Basil                       $01.70
Bath soap / Hand soap       $06.75
Bathroom cleaner            $04.55
_
Category                    Cost
====                        ====
Spices                      $1.7
Baby/Pet                    $14
Condiments                  $8.55
Produce                     $23
Soap/Sundry                 $10.55
Baking                      $7.85
Bread                       $10.35
Cleaner/Detergent           $15.15
_
Total                       Cost
====                        ====
Total                       $91.15

如果没有示例输入和预期输出,就很难理解您想要做什么achieve@RomanPerekhrest我添加了一些示例输入和输出,谢谢。为什么有
浴室清洁剂
百吉饼/羊角面包
和其他产品从产出中漏掉了?当所有投入的总额远远低于这一数字时,如何获得195.45美元的产品小计。显然,您需要确保您提供的预期输出是您提供的输入的预期输出,不是来自其他输入的输出,否则,当我们根据您的输入测试可能的解决方案时,我们如何知道它产生的输出是否正确?实际列表超过100项,因此我发布了样本,没有样本输入和预期输出-很难理解您想要什么achieve@RomanPerekhrest我加了一些样本输入和输出,谢谢。为什么
浴室清洁器
面包圈/羊角面包
和其他东西从输出中漏掉了?当所有输入的总额远远低于这个数字时,你如何获得195.45美元的产品小计。显然,您需要确保您提供的预期输出是您提供的输入的预期输出,而不是其他输入的输出,否则,当我们根据您的输入测试可能的解决方案时,我们如何知道它产生的输出是否正确?实际列表超过100项,因此我发布了示例谢谢,我也很感激这些文档!谢谢,我也很感激这些文档!
$ awk -f tst.awk file |
  awk 'BEGIN{FS=OFS="\t"} $1!=p{print "_" ORS $1, "Cost" ORS "====", "===="; p=$1} {print $2, "$"$3}' |
  column -s$'\t' -t
_
Item                        Cost
====                        ====
Air freshener               $10.60
Antiperspirant / Deodorant  $03.80
Apples                      $10.80
Asparagus                   $01.05
Avocados                    $08.25
BBQ sauce                   $08.55
Baby food                   $08.60
Baby wash                   $05.40
Bagels / Croissants         $10.35
Baking powder / Soda        $07.85
Bananas                     $02.90
Basil                       $01.70
Bath soap / Hand soap       $06.75
Bathroom cleaner            $04.55
_
Category                    Cost
====                        ====
Spices                      $1.7
Baby/Pet                    $14
Condiments                  $8.55
Produce                     $23
Soap/Sundry                 $10.55
Baking                      $7.85
Bread                       $10.35
Cleaner/Detergent           $15.15
_
Total                       Cost
====                        ====
Total                       $91.15