Bash数学 - 使用for语句划分一堆行

时间:2016-04-11 04:06:43

标签: bash for-loop

示例文件:

    25      Firstname1 Lastname1     domain1.com    planname    @1.00 USD       Monthly Active  04/24/2016      Edit
    1068    Firstname2 Lastname2     domain2.com    planname   @7.95 USD       Annually Active  05/09/2016      Edit
    3888    Firstname3 Lastname3     domain3.com    planname    @19.95 USD      Biennially Active  05/04/2016      Edit

我只提取价格和结算周期,并将结算周期转换为数值,这样我可以将价格除以结算周期,以获得每月的费用。

当使用for语句时,它的添加行会破坏数学。

代码:

    for i in `cat asd | cut -d "@" -f 2 | awk '{print $1, $3}' | sed 's/Monthly/\/ 1/g' | sed 's/Annually/\/ 12/g' | sed 's/Biennially/\/ 24/g' |grep -Ev 0.00` ; do echo $i | bc -l' ; done

我希望能够获得1个答案,这意味着所有行都被分割,然后加在一起得到最终答案。

2 个答案:

答案 0 :(得分:1)

所有这些来自catcutawksedgrepbc的来电 - 真是浪费。

这是一个错误命名的帖子,因为您没有使用Bash进行任何计算。原因是bash与korn shell(ksh)不同,不支持浮点。所以你回到bc这样的实用程序。但请坚持,awk也支持浮点。

awk本身就是一种编程语言。这仅使用awk的一个实例。我已经将它嵌入到bash脚本中,因为你可能正在做其他的事情,但稍微调整它可以独立于#!/bin/awk顶部:

infile='asd'

# -f - means "read the program from stdin"
# << '_END_' is a here document.  Redirect stdin from here to the label _END_
awk -f - "$infile" << '_END_'
BEGIN {
# an associative array for the billing cycles
cycles["Monthly"]    = 1
cycles["Annually"]   = 12
cycles["Biennially"] = 24
}

{
sub(/@/,"",$6)          # Remove the @ from the amount
total += $6/cycles[$8]  # divide amount by the billing cycle, add to total
}
END { print total }
_END_

难道您不认为理解和维护更简单吗?它也更有效率。这个awk脚本可能是 awk 101 培训课程的一个很好的练习。

答案 1 :(得分:0)

你可以做这样的事情:(如果你完全设置在一条线上)

cat asd | cut -d "@" -f 2 | awk '{print $1, $3}' | sed 's/Monthly/\/ 1/g' | sed 's/Annually/\/ 12/g' | sed 's/Biennially/\/ 24/g' | grep -Ev 0.00 | while IFS= read -r line; do echo "$line" | bc -l; done | tr '\n' '+' | sed 's/+$/\n/' | bc -l

但这会更清楚:

tmp=$(mktemp)
cat asd | cut -d "@" -f 2 | awk '{print $1, $3}' | sed 's/Monthly/\/ 1/g' | sed 's/Annually/\/ 12/g' | sed 's/Biennially/\/ 24/g' | grep -Ev 0.00 > $tmp

tmp2=$(mktemp)
cat $tmp | while IFS= read -r line; do
  echo "$line" | bc -l >> $tmp2
done

# Actual output
cat $tmp2 | tr '\n' '+' | sed 's/+$/\n/' | bc -l
rm $tmp $tmp2