平均値を印刷するシェルプログラム

平均値を印刷するシェルプログラム

私がしなければならないことは、ファイルからデータを含む行を読み取るavgsという名前のシェルプログラムを書くことです。ここで、ヘッダー行はデータのどこにでも存在できます。

最後の2つの列の合計を計算して計算する必要があり、合計と計算に最初の行のデータを含めないでください。

以下はデータを含むファイルです。

92876035 SMITZ  S 15 26
95908659 CHIANG R 10 29
SID      LNAME  I T1/20 T2/30
92735481 BRUCE. R 16 28
93276645  YU    C 17 27
91234987 MYRTH  R 15 16

シェルプログラムは、標準出力に次の行を書き込みます: "Theaverage is 17 and 24"

これは私が試したものですが、うまくいきません

count_ppl=0
total=0
while read ?? ?!
do
    total=$((sum+b))
    count_ppl=$((count_ppl+1))
done < filename
avg=$(echo "scale=2;$total/$count_ppl" | bc)
echo "The averages are = $avg"

「読んでいる間」の横に「??」と「?!」があるのは、そこに何を入れるべきかわからないからです。

これは1つの列の1つの平均を計算できるようですが、列からデータを取得して2つの平均を計算するにはどうすればよいですか?

(ところで、これはbashです)。

答え1

「最初の行のデータは合計と数に含まれてはいけません」という言葉が何を意味するのかわかりません。 「92876035 SMITZ S 15 26」行を除外する必要がありますか、それとも「SID LNAME I T1/20 T2/30」が「合計」されていないという意味ですか?

必要な変数名に変更する??必要があります。?!最後に言及された変数名は残りの入力を保持します。最後の2つの列が必要なので、あなたの場合は5つの列があり、ステートメントは次while readのようになります。

while read col1 col2 col3 col4 col5

次に、行がヘッダー行であることを確認する必要があります。この例では、最初の列のSIDという単語をテストします。

if [ "$col1" != 'SID' ]

ここから計算を開始できます。

totallines=$((totallines+1))
sumcol4=$((sumcol4+col4))
sumcol5=$((sumcol5+col5))

最後に、以下を使用して平均を計算できます。

avgcol4=$(echo "scale=2; $sumcol4/$totallines"|bc)
avgcol5=$(echo "scale=2; $sumcol5/$totallines"|bc)

終了するには、次のスクリプトを使用できます。

#!/bin/bash
while read col1 col2 col3 col4 col5
do
  if [ "$col1" != 'SID' ]
  then
      totallines=$((totallines+1))
      sumcol4=$((sumcol4+col4))
      sumcol5=$((sumcol5+col5))
  fi
done < /path/to/inputfile
avgcol4=$(echo "scale=2; $sumcol4/$totallines"|bc)
avgcol5=$(echo "scale=2; $sumcol5/$totallines"|bc)
printf "The averages are %s and %s" $avgcol4 $avgcol5

別の方法は、次のものを使用することですawk

awk '{ if ( $1 != "SID" ) { COL4+=$4; COL5+=$5; } } END { LINES=NR-1; printf "The averages are %.2f and %.2f\n", COL4/LINES, COL5/LINES }' < /path/to/inputfile

上記のコマンドはヘッダー行をフィルタリングし、そうでない場合は列4と5を合計します。入力ファイルを処理したら、LINES変数をレコード数から1(ヘッダ行)を引いた数に設定し、出力ラインを印刷します。

bashバージョンがawk出力されます。

The averages are 14.60 and 25.20

答え2

#!/usr/bin/awk -f

NR == 1     { next }
/^[^0-9]/   { next }

{
    s1 += $(NF - 1)
    s2 += $NF
    ++n;
}

END {
    printf("The averages are %.2f and %.2f\n", s1/n, s2/n)
}

テスト:

$ chmod +x avgs
$ ./avgs file
The averages are 14.50 and 25.00

awkこれは、データの最初の行(質問で要求されているように)と最初の文字として数値以外の値を含むすべての行をスキップするために使用されます。

他のすべての行では、最後の2つのフィールドの数字をtwe sumに追加し、カウンターs1s2増やしますn

最後に、結果を小数点以下の2桁まで出力します。

シェルの「ライン」で:

$ awk 'NR==1||/^[^0-9]/{next} {s1+=$(NF-1);s2+=$NF;++n} END {printf("The averages are %.2f and %.2f\n", s1/n, s2/n)}' file
The averages are 14.50 and 25.00

関連:

関連情報