別の入力ファイル内の特定の行範囲の列平均を計算します。

別の入力ファイル内の特定の行範囲の列平均を計算します。

あるファイルで指定された特定の範囲の平均を計算し、それを別のファイルの数に適用したいとします。同時に、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 

おすすめ記事