脚本

脚本

这是我试图从中提取信息的文件 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

注释/解释

  1. 调用该awk命令,将字段分隔符设置为逗号 ( ,),并传递本行单引号和下面几行下一个单引号之间的所有内容,如脚本所示:

    awk -F, '
    
  2. Skip Header:如果当前记录号为1,则跳过当前行(第一行)的所有处理,并获取下一行输入:

        NR == 1 {
            next                        # skip header
        }
    
  3. 累积每个品牌的总价格(这在每行上执行):
    数组price_paidcount由字符串索引brand
    将当前支付价格 ( $3) 添加到该品牌的price_paid 总额中。
    增加该品牌的记录数:

        {
            price_paid[$4] += $3        # accumulate total price for this brand    
            count[$4] += 1              # increment count of records for this brand
        }
    
  4. 打印输出表:处理完所有输入后,逐步通过键 ( brand) 到达price_paid数组,并为每个brand打印和的brand平均值:price_paidbrand

        END {
            for (brand in price_paid) {
                printf "%s,%7.2f\n", brand, price_paid[brand] / count[brand]
            }
       }
    
  5. 终止脚本参数,重定向来自文件名参数的输入,并将命令的输出通过管道传输awksort命令:

    ' < "${1:?filename required}" | sort
    

单引号 ( ') 终止 的脚本参数awk。将第一个命令行参数指定的文件名
< "${1:?filename required}"的标准输入重定向awk到脚本。如果没有参数,那么 shell 将打印一条包含“filename required”的错误消息,并以错误状态退出。

相关内容