あるファイルで指定された特定の範囲の平均を計算し、それを別のファイルの数に適用したいとします。同時に、2つの別々のファイルの情報をbashで使用する例が見つかりません。これが私がしたいことです:
最初のファイルは、平均を求める範囲を指定します。
範囲.txt
Sc0 1 5
Sc1 69 72
2番目のファイルには、3番目の列を使用して平均を取得するために必要な数字が含まれています。
すべての番号.txt
Sc0 1 30
Sc0 2 40
Sc0 3 40
Sc0 4 50
Sc0 5 10
Sc0 6 30
Sc1 69 40
Sc1 70 10
Sc1 71 20
Sc1 72 30
これが私が望むものです: 平均.txt
34
25
以下に示すbashループでこれを実行しようとしています。しかし、私はbashスクリプトに初めてアクセスしたので、このコードは機能しません。
#!/bin/bash
count=0;
total=0;
while read rangeName rangeStart rangeStop #make column variables for range.txt
while read name position sum #make column variables for allNumbers.txt
while [$rangeName == $name && $rangeStart < $position <= $rangeStop]; do
for i in $sum; do
total=$(echo $total+$i | bc)
((count++))
done
echo "$total / $count" | bc #print out averages
done
done < allNumbers.txt
done < ranges.txt
誰でもこの問題を解決するのに役立ちますか?よろしくお願いします。
ベストアンサー1
実際にこれにシェルを使用したくありません。まず、浮動小数点演算を実行しないため、呼び出すかbc
他の操作を実行する必要があります。第二に、見てわかるように、構文は非常に複雑なためです。遅い。バラよりシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?詳細については。
他のほとんどすべての言語が優れていますが、使用できる1つのアプローチは次のとおりですawk
。
$ awk 'NR==FNR{a[$1]["start"]=$2; a[$1]["end"]=$3; next}
{
if($2>=a[$1]["start"] && $2<=a[$1]["end"]){
values[$1]+=$3;
nums[$1]++;
}
}
END{
for(range in values){
print values[range]/nums[range]
}
}' ranges allNumbers
34
25
これはコメント付きのスクリプトと同じです。
#!/bin/awk -f
## If we are reading the first file
NR==FNR{
## $1 is the range name, so this will save the
## start position for this range name as a[$1]["start"] and
## the end position as a[$1]["end"]
a[$1]["start"]=$2;
a[$1]["end"]=$3;
## skip to the next line
next
}
## This will only run for the second file
{
## If this value falls in the relevant range
if($2>=a[$1]["start"] && $2<=a[$1]["end"]){
## Sum the values of this range and save
## in the values array
values[$1]+=$3;
## Count the number of values for this range and save
## in the 'nums' array.
nums[$1]++;
}
}
## After we've read both files
END{
## For each range in the 'values' array
for(range in values){
## print the average
print values[range]/nums[range]
}
}
最初のコード行を実行するか、上記のコードを保存してfoo.awk
実行可能にして実行できます。
foo.awk ranges allNumbers