这是我试图从中提取信息的文件 car_sales.txt 的“小”部分(完整文件大约有 700 行,其中车辆品牌比此处列出的更多):
first_name,last_name,price_paid,brand,year Mann,Mathers,20500.79,Chevy,2012 Doug,Samual,21000.12,Dodge,2015 Walter,Gray,17000.87,Dodge,2010 Jessica,Garnet,17350.00,MINI,2009 Paula,Raymond,45300.87,BMW,2015 Willie,Reynolds,64950.05,BMW,2015 Sam,Collins,70200.35,Lexus,2014 Katy,Martinez,29580.84,Chevy,2012 Nicole,Davis,31650.60,Chevy,2009 Brenda,Gray,12400.56,Dodge,2012 Samantha,Fernandez,27900.21,MINI,2015 Eric,Woods,68900.85,BMW,2009 George,Luke,33453.91,BMW,2011 Mildred,Takey,46820.80,Lexus,2012
我想输出“brand”和“price_paid”列(并找到所有汽车的每个品牌支付的平均价格),排序(az),并删除第一行“标题”。这是我正在寻找的输出(来自上面列出的示例):
BMW,53151.4 Chevy,27244.1 Dodge,16800.5 Lexus,58510.6 MINI,22625.1
现在我已经花了两天时间试图解决这个问题,但没有运气(我对此很陌生),我能想到的最好的办法是:
sed '1d' car_sales.txt |awk -F ',' '/Chevy/{print $3}' $1|awk '{total += $1; count ++}END{print "Chevy," total/count}'
现在显然这“不是”我正在寻找的;如果我只需要“一个”品牌/已付价格的平均输出,那么是的,它会起作用,我只需输入我正在寻找的单个“模式”,然后我就会得到支付的平均价格。
不过,我正在寻找一种方法来捕获并输出 car_sales.txt 文件中所有品牌的平均价格。除了我列出的部分中的 5 个之外,还有很多品牌(大约 50 多个品牌)。
我已经读了我拥有的三本书,并在网上浏览了几个小时,但我一生都无法弄清楚。也许我什至没有找对地方,我以为 awk 就是答案,但它太大了。非常感谢您提前的帮助。
然后我有了一个想法,认为我已经找到了实现它的方法,并开始编写这个脚本。从逻辑上讲,它似乎在我的脑海中起作用,我的想法是我将使用第一个函数的输出作为第二个函数的输出。唉,这也不起作用,我以为我走在正确的道路上,但事实并非如此。
#!/bin/bash
#This will output the car "brand"
function brand {
sed '1d' $1| cut -d ',' -f 4 |sort|uniq
}
#The output of function "brand", will be the pattern for function "average"
function average {
awk -F ',' '/'"$names"'/{print $3}' $1|awk '{total += $1; count ++}END{print "'$names'" "," total/count}'
}
brand $1
names=$(brand)
average $1 $names
答案1
由于awk
数组是按字符串索引的,因此您可以使用一个数组来保存该品牌迄今为止的总价格,并使用另一个数组来保存该品牌的记录数。
awk
因为“brand”是字段 4,所以您可以像这样索引数组:
total_price[$4] += $3 # accumulate total price for this brand
count[$4] += 1 # increment count of records for this brand
最后,循环访问数组的键,并在计算平均值时格式化输出。
由于 POSIXawk
不包含排序函数,因此将命令的输出通过管道传输awk
到标准 Unixsort
命令。
请尝试这个:
脚本
#!/bin/sh
#first_name,last_name,price_paid,brand,year
#print for each brand, the average price paid
awk -F, '
NR == 1 {
next # skip header
}
{
price_paid[$4] += $3 # accumulate total price for this brand
count[$4] += 1 # increment count of records for this brand
}
END {
for (brand in price_paid) {
printf "%s,%7.2f\n", brand, price_paid[brand] / count[brand]
}
}
' < "${1:?filename required}" | sort
注释/解释
调用该
awk
命令,将字段分隔符设置为逗号 (,
),并传递本行单引号和下面几行下一个单引号之间的所有内容,如脚本所示:awk -F, '
Skip Header:如果当前记录号为1,则跳过当前行(第一行)的所有处理,并获取下一行输入:
NR == 1 { next # skip header }
累积每个品牌的总价格(这在每行上执行):
数组price_paid
和count
由字符串索引brand
。
将当前支付价格 ($3
) 添加到该品牌的price_paid 总额中。
增加该品牌的记录数:{ price_paid[$4] += $3 # accumulate total price for this brand count[$4] += 1 # increment count of records for this brand }
打印输出表:处理完所有输入后,逐步通过键 (
brand
) 到达price_paid
数组,并为每个brand
打印和的brand
平均值:price_paid
brand
END { for (brand in price_paid) { printf "%s,%7.2f\n", brand, price_paid[brand] / count[brand] } }
终止脚本参数,重定向来自文件名参数的输入,并将命令的输出通过管道传输
awk
到sort
命令:' < "${1:?filename required}" | sort
单引号 ( '
) 终止 的脚本参数awk
。将第一个命令行参数指定的文件名
< "${1:?filename required}"
的标准输入重定向awk
到脚本。如果没有参数,那么 shell 将打印一条包含“filename required”的错误消息,并以错误状态退出。