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