スクリプト

スクリプト

これは情報を抽出したい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)して、最初の行「title」を削除しようとしています。これは私が探している結果です(上記の例では)。

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}'

明らかに、これは私が探しているものではありません。 「1つの」ブランド/支払い価格の平均生産量だけが必要な場合は、はい。私が探している単一の「パターン」を入力するだけです。では平均価格をお支払いいたします。

しかし、car_sales.txtファイルからすべてのブランドの平均価格をキャプチャして出力する方法を探しています。私がリストしたセクションにある5つのブランドに加えて、より多くのブランド(約50以上)があります。

私は私が所有している3冊の本を読んでオンラインで数時間検索しましたが、生涯にわたってその内容を理解できません。たぶん私は正しい場所を探していないかもしれません。 awkが答えだと思いましたが、大きすぎます。事前に助けてくれてありがとう。

その後、アイデアが浮かび上がり、これを行う方法を見つけたと考えて、このスクリプトを作成し始めました。論理的には、私の頭の中で動作するようです。最初の関数の出力を2番目の関数の出力として使用するという考えです。ああ、これも動作しません。私は正しい道を行っていると思ったが、そうではなかった。

#!/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「ブランド」はフィールド4なので、次のように配列にインデックスを付けることができます。

total_price[$4] += $3        # accumulate total price for this brand
count[$4] += 1               # increment count of records for this brand

最後に、配列のキーを繰り返し、平均を計算しながら出力フォーマットを指定します。

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

コメント/説明

  1. コマンドを呼び出し、フィールド区切りawk文字をコンマ(,)に設定し、スクリプトに示されているように、この行の一重引用符と数行以下の次の一重引用符の間のすべての内容を渡します。

    awk -F, '
    
  2. ヘッダーをスキップする:現在のレコード番号が1の場合、現在の行(最初の行)のすべての処理をスキップして次の入力行を取得します。

        NR == 1 {
            next                        # skip header
        }
    
  3. ブランド別の合計価格を累積します(各行で行われます)。文字列でインデックス付けされた
    配列の合計。ブランド総価格_支払額に現在の支払価格()を加算します。このブランドの記録数を増やしてください。 price_paidcountbrand
    $3

        {
            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印刷します。brandprice_paidbrand

        END {
            for (brand in price_paid) {
                printf "%s,%7.2f\n", brand, price_paid[brand] / count[brand]
            }
       }
    
  5. スクリプト引数を終了し、filename引数の入力をリダイレクトし、コマンドの出力をコマンドにパイプawkします。sort

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

一重引用符(')はスクリプトパラメータを終了しますawk。最初のコマンドライン引数で指定されたファイル名
< "${1:?filename required}"の標準入力をawkスクリプトにリダイレクトします。引数がない場合、シェルは「ファイル名が必要」を含むエラーメッセージを出力し、エラー状態で終了します。

おすすめ記事