从单独的输入文件计算特定行范围内的列平均值

从单独的输入文件计算特定行范围内的列平均值

我正在尝试计算一个文件中指定的给定范围内的平均值,并将其应用于不同文件中的数字。我在 bash 中找不到可以同时使用 2 个单独文件中的信息的示例。这就是我想做的:

第一个文件指定了我想要平均值的范围:

范围.txt

Sc0  1  5
Sc1  69 72

第二个文件包含我需要从中获取平均值的数字(使用第三列):

所有数字.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

您确实不想为此使用 shell。首先,因为它不执行浮点数学运算,因此您需要调用bc或其他工具;第二,如您所见,因为语法非常复杂;第三,因为它是慢的。看为什么使用 shell 循环处理文本被认为是不好的做法?更多细节。

几乎任何其他语言都会更好,但这是一种使用的方法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 

相关内容