从文件输出多组行的平均值的脚本

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)

Rob*_*rtL 5

由于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)

注释/说明

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

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

        NR == 1 {
            next                        # skip header
        }
    
    Run Code Online (Sandbox Code Playgroud)
  3. Accumulate Price Total Per Brand(这在每一行上执行):
    数组price_paidcountbrand字符串索引。
    将当前支付的价格 ( $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)
  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]
            }
       }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 终止脚本参数,重定向来自文件名参数的输入,并将awk命令的输出通过管道传输到sort命令:

    ' < "${1:?filename required}" | sort
    
    Run Code Online (Sandbox Code Playgroud)

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