如何组合排序、计算平均值和打印的 bash 脚本?

How do I combine a bash script that sorts, calculates an average, and prints?

我们不能使用awk或者新建一个文件来存储数据。

我的脑子解决不了这个问题。我们得到了这样的数据集:

299226663 Laney Camp 70 74 71 
434401929 Skyler Camp 78 81 82 
199144454 Tracey Camp 77 84 84 

我们必须计算平均值,并像这样打印结果:

71 [299226663] Camp, Laney  
80 [434401929] Camp, Skyler 
81 [199144454] Camp, Tracey

我有单独的 bash 代码段,它们都可以工作,但我不知道如何组合它们。

这是正确的排序方式

sort -t' ' -k3,3 -k2,2 -k1,1n StudentGrades.txt

接下来的部分肯定是错误的,我希望它会被撕裂,但它确实计算了平均值并打印了正确的格式,除了它出于某种原因跳过了 StudentGrades.txt 的最后一行:

filename='StudentGrades.txt'

while read LINE
do 
var1=$(echo $LINE | cut -d' ' -f1)
var2=$(echo $LINE | cut -d' ' -f2)
var3=$(echo $LINE | cut -d' ' -f3)
var4=$(echo $LINE | cut -d' ' -f4)
var5=$(echo $LINE | cut -d' ' -f5)
var6=$(echo $LINE | cut -d' ' -f6)

let a=(var4+var5+var6)/3
echo $a [$var1] $var3, $var2 


done < StudentGrades.txt

如果不将第二个脚本移动到新文件并对其调用排序命令,我想不出一种方法来获取平均值、格式和排序。有任何想法吗?它可能需要更大的改变,因为我对第二部分没有信心,哈哈。

我不知道你为什么对平均循环如此怀疑:除了你对整数进行取整外,它看起来还不错。

没有任何变化,或多或少只是简单地把它们放在一起:

#!/bin/bash
input_file="StudentGrades.txt"

(cat "$input_file" ; echo "") | \
sort -t' ' -k3,3 -k2,2 -k1,1n | \
while read LINE
do 
  var1=$(echo $LINE | cut -d' ' -f1)
  var2=$(echo $LINE | cut -d' ' -f2)
  var3=$(echo $LINE | cut -d' ' -f3)
  var4=$(echo $LINE | cut -d' ' -f4)
  var5=$(echo $LINE | cut -d' ' -f5)
  var6=$(echo $LINE | cut -d' ' -f6)

  let a=(var4+var5+var6)/3
  echo $a [$var1] $var3, $var2 
done

cat 之后的 echo "" 只有在文件的最后一行没有被正确读取的情况下才需要(发生这种情况是因为 read 等待换行符,但是你的文件可能不以换行符结尾)。

\ 符号使代码看起来好像没有换行符,因此命令通过管道连接在一起。通过添加足够多的分号,如果您真的愿意,您甚至可以将其写在一行中。


通过@JonathanLeffler 提出的重构:

#!/bin/bash
input_file="StudentGrades.txt"

(cat "$input_file" ; echo "") | \
sort -t' ' -k3,3 -k2,2 -k1,1n | \
while read num_id name surname points1 points2 points3
do 
  let average=(points1+points2+points3)/3
  echo ${average} [${num_id}] $surname, $name
done

似乎与其他版本一样工作。

哈,在 bash 学到了新东西!谢谢@JonathanLeffler! :)

关于缺少最后一行的问题,这是read命令的一个常见缺陷 因为如果该行末尾不包含换行代码,它 returns false 行,通常出现在最后一行,具体取决于文本编辑器。
作为解决方法,尝试 while read LINE || [ -n "${LINE}" ] 而不是 while read LINE.
除此之外,考虑说 set -- $LINE 而不是分别用 cut 命令拆分。它会自动将每一列分配给位置参数 $1、$2 等。然后你的脚本会运行得更快。 顺便说一句,您的平均计算会截断小数部分而不将其四舍五入为最接近的整数。可以吗?

综上所述,我将按如下方式修改您的脚本:

#!/bin/bash

sort -t' ' -k3,3 -k2,2 -k1,1n StudentGrades.txt | while read LINE || [ -n "${LINE}" ]; do
    set -- $LINE

    let a=(*10 + *10 +*10 + 15)/30
    # If you want to preserve the 1st decimal place, replace the line above with:
    # a=$( echo $(( (*10 + *10 +*10 ) / 3 )) | sed -e "s/\(.\)$/./" )

    echo $a [] , 

done