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

时间:2018-02-08 23:33:21

标签: bash sorting piping

我们无法使用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

我无法找到获得平均值,格式化和排序的方法,而无需将第二个脚本移动到新文件并在其上调用sort命令。有任何想法吗?它可能会采取更大的变化,因为我对第二部分没有信心。

2 个答案:

答案 0 :(得分:1)

我不知道为什么你对平均循环如此持怀疑态度:除了你是整数之外,看起来还不错。

没有任何改变,或多或少简单地将它们全部输送到一起:

#!/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

仅在文件的最后一行未正确读取的情况下才需要echo ""之后的cat(这是因为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! :)

答案 1 :(得分:0)

关于丢失的最后一行问题,这是read命令的常见缺陷 因为如果该行末尾不包含换行代码,则返回false 该行的常常出现在最后一行,具体取决于文本编辑器 要解决此问题,请尝试while read LINE || [ -n "${LINE}" ]而不是while read LINE 除此之外,请考虑说set -- $LINE而不是分别使用cut命令。它会自动将每列分配到正面参数$ 1,$ 2等等。然后你的脚本将更快地工作。 BTW你的平均计算截断小数部分而不将其四舍五入到最接近的整数。那可以吗?

总结一下,我会修改你的脚本如下:

#!/bin/bash

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

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

    echo $a [$1] $3, $2

done