【问题标题】:How to find every number in a row and store average in separate per-row variable如何查找一行中的每个数字并将平均值存储在单独的每行变量中
【发布时间】:2012-10-07 22:59:59
【问题描述】:

我刚开始学习 shell 脚本。

我正在尝试从结构如下的文件中读取:

harddrive1 10 20 30 40
harddrive2 20 30 40 50
harddrive3 30 40 50 60

我想以某种方式将每行的平均值保存在一个单独的变量中……只有 3 行 5 列。 所以我的输出是:

hd_AVG1=20
hd_AVG2=35
hd_AVG3=45

我怎样才能做到这一点?

编辑:我需要将它保存在不同的变量中,以便我可以调用该变量...例如

if [[ $hd_AVG1 -eq 20 ]];
    then 
    do something...
elif [[ $hd_AVG2 -gt 40 ]];
    then
    do something...
fi

【问题讨论】:

  • 如果有的话,看看你目前使用什么代码来读取这样的文件会很酷。如果您没有代码,请先google。
  • 根据“某物”是什么,您可能会在 shell 中走错路。此外,您正在使用 [[ 与算术表达式和 -gt 等混合外壳样式/构造。您应该使用 if (( hd_AVG1 > 40 )) 等。

标签: bash shell unix awk aix


【解决方案1】:
$ awk '{print $1"="($2+$3+$4+$5)/4}' file
harddrive1=25
harddrive2=35
harddrive3=45

【讨论】:

  • 它工作正常,但问题出在这里....我想将它保存为不同的变量 hd1..not harddrive1
  • 打印 "hd" NR "=" ($2+$3+$4+$5)/4
  • @EdMorton Morton 好的,如果我替换它,unix 会显示我想要的信息。然而,当我做 echo $hd1 我得到 harddrive1 echo $hd2 我什么也没得到...... :(
  • 你没有说你需要填充一个 SHELL 变量。您获得的大多数解决方案都填充 awk、perl 等变量,或者只是打印您想要的标准输出。您可以在 awk 命令之前粘贴“eval”:eval awk '...' 以设置名为 hd1 等的 shell 变量。
  • 啊抱歉,这是我第二次写 shell 脚本了 :(
【解决方案2】:

这个 bash 脚本应该做你想做的事。它调用bc 来进行浮点运算,因为 bash 不能自己做。

#!/bin/bash
while read -a line ; do
    sum=0
    for ((i=1; i<${#line[@]}; i++)) ; do
        let sum+=line[i]
    done;
    hd[j++]=$(bc -l <<< "$sum/($i-1)")
done < input
echo ${hd[0]} ${hd[1]} ${hd[2]}

【讨论】:

  • 我不确定我是否正确理解了您的代码,此代码是否将第 1 行结果保存到变量 1,第 2 行结果保存到变量 2 等等...?
  • &lt;=更改为&lt;($i-2)更改为($i-1);这避免了循环的不必要迭代,其中line[i] 始终是最终的空字符串。
  • 没有人会认真地在 shell 中编写一个 while 循环,调用 bc 只是为了添加一些数字。请参阅@guru 发布的 awk 解决方案。
  • 你可以用 hd=($(awk '{print ($2+$3+$4+$5)/4}' input))。请参阅我在下面发布的答案。
【解决方案3】:

使用Perl(非常便携):

perl -lane 'print $F[0] . "=" . ($F[1] + $F[2] + $F[3] + $F[4]) / 4' file.txt

【讨论】:

  • 这基本上和大师的回答一样,它不会将每一行的结果保存到我可以实际调用和使用的变量中:(
  • 好像你自己没有努力去理解任何东西。
【解决方案4】:

使用我刚刚从 @steve 那里学到的数组填充技巧:

$ cat file
harddrive1 10 20 30 40
harddrive2 20 30 40 50
harddrive3 30 40 50 60
$
$ hd_AVG=($(awk '{print ($2+$3+$4+$5)/4}' file))
$ echo "${hd_AVG[0]}"
25
$ echo "${hd_AVG[1]}"
35
$ echo "${hd_AVG[2]}"
45

【讨论】:

    【解决方案5】:

    你可以像这样使用 coreutils 和 sed:

    . <(paste -d=                                                   \
          <(cut -d' ' -f1  infile                                 ) \
          <(cut -d' ' -f2- infile  | sed 's/$/ + + + 4 \/ p/' | dc) \
       )
    echo $harddrive1 $harddrive2 $harddrive3
    

    输出:

    25 35 45
    

    说明

    &lt;( ) 表示法在其中运行命令并通过 fifo 管道输出它们,因此 paste 看到两个管道并使用 = 作为它们的分隔符将它们的输出列列。

    第二个cut 从文件中获取数字,sed 将适当的运算符附加到数字并让dc 进行计算。 dc 的输入如下所示:

    cut -d' ' -f2- infile | sed 's/$/ + + + 4 \/ p/'
    

    输出:

    10 20 30 40 + + + 4 / p
    20 30 40 50 + + + 4 / p
    30 40 50 60 + + + 4 / p
    

    dc 是一个逆波兰计算器;它支持任意精度,但需要被告知使用小数。这将使dc 使用两位小数:

    cut -d' ' -f2- dims | sed 's/^/2k/; s/$/ + + + 4 \/ p/'
    

    整个命令也包含在&lt;( ) 中并以. 为源,即变量将在当前环境中可用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多