Jay*_*een 4 linux shell bash sed awk
这是我试图从中提取信息的文件 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
现在我一直在努力解决这个问题,但已经有 2 天没有运气了(我是新手),我能想到的是:
sed '1d' car_sales.txt |awk -F ',' '/Chevy/{print $3}' $1|awk '{total += $1; count ++}END{print "Chevy," total/count}'
Run Code Online (Sandbox Code Playgroud)
现在很明显,这就是我要找的“不是”;如果我只需要“一个”品牌/价格_付费的平均输出,那么是的,它会起作用,我只需输入我正在寻找的单个“模式”,然后我就会得到平均价格。
但是,我正在寻找一种方法来捕获和输出为 car_sales.txt 文件中所有品牌支付的平均价格。还有很多品牌,然后我列出的部分中只有 5 个(大约 50 多个品牌)。
我已经阅读了我拥有的 3 本书并在网上扫描了几个小时,对于我的生活,我无法弄清楚。也许我什至没有找对地方,我认为 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
Run Code Online (Sandbox Code Playgroud)
由于awk
数组是由字符串索引的,因此您可以使用一个数组来保存该品牌目前的总价格,并使用另一个数组来保存该品牌的记录数。
因为“brand”是字段 4,你可以awk
像这样索引数组:
total_price[$4] += $3 # accumulate total price for this brand
count[$4] += 1 # increment count of records for this brand
Run Code Online (Sandbox Code Playgroud)
最后,遍历数组的键,并在计算平均值的同时格式化输出。
由于 POSIX 不awk
包含排序功能,因此将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
Run Code Online (Sandbox Code Playgroud)
调用该awk
命令,将字段分隔符设置为逗号 ( ,
) 并在此行的单引号和下面几行的下一个单引号之间传递所有内容,作为脚本:
awk -F, '
Run Code Online (Sandbox Code Playgroud)Skip Header:如果当前记录号为1,则跳过当前行(第一行)的所有处理,获取下一行输入:
NR == 1 {
next # skip header
}
Run Code Online (Sandbox Code Playgroud)Accumulate Price Total Per Brand(这在每一行上执行):
数组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
}
Run Code Online (Sandbox Code Playgroud)打印输出表:所有输入被处理之后,步骤通过键(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]
}
}
Run Code Online (Sandbox Code Playgroud)终止脚本参数,重定向来自文件名参数的输入,并将awk
命令的输出通过管道传输到sort
命令:
' < "${1:?filename required}" | sort
Run Code Online (Sandbox Code Playgroud)单引号 ( '
) 将脚本参数终止为awk
。
< "${1:?filename required}"
将awk
来自第一个命令行参数指定的文件名的标准输入重定向到脚本。如果没有参数,则 shell 将打印一条包含“需要文件名”的错误消息并以错误状态退出。