bc command in shell

昨天在工作中遇到这么一个问题, 在shell中比较浮点数和整数的大小. 原本以为用shell的比较符号(-lt之类的)就可以, 没想到一试不行.
问了度娘后才发现, shell原则上是不支持浮点数计算的.
因为着急用, 就随便找了个帖子说可以这么比:

1
2
>  expr $a \> $b
>

我没test就直接先push到公司的repo了, reviewer估计也没用过, 看了下就merge了.
今天跑脚本才发现根本就不能这么用啊, holy shit. 最后找到了bc这个神器, 问了下度娘, 都没什么好文章. 索性就直接上官网看manual.
好了, 废话说了一大堆, 现在来说说bc吧:)

首先, bc可以是交互性的, 也支持在管道符后面使用.
所以一些复杂的有关浮点数的运算, 完全可以结合expect脚本, 个人感觉会很方便. 如果用awk算, 估计会吐…
像我昨天遇到的普通运算完全就可以用管道啦.
一般来说在脚本中可以这么用:

1
a=$(bc << EOF
  28.3 * 55.8
  EOF)

bc可以说totally就是一门语言. 有变量, 有逻辑控制, 亦有函数.

基本元素

  • 数字
    最基本的元素, 可以是整数也可以是浮点数. manual里说支持任意精度, 注意这任意两字, 有没有碉堡了.
  • 变量
    变量可以是简单变量, 也可以是数组. 变量的命名以任意字母开头, 中间可以是任意数字/字母/下划线. 但有一点需要注意, 字母必须都是小写.
    数组是用方括号表示.
    有四个特殊的变量: scale, ibase, obase和last. scale表示小数点后位数, ibase和obase表示input和output是什么进制的, 我们这里不做说明, 有兴趣的同学可以直接看manual. last表示最后一个打印的数值.
  • 注释
    多行注释: /* …… */
    单行注释: #

支持的运算

加减乘除/乘方/地板除/自加/自减

摘自manual:
- expr
The result is the negation of the expression.
++ var
The variable is incremented by one and the new value is the result of the expression.
– var
The variable is decremented by one and the new value is the result of the expression.
var ++
The result of the expression is the value of the variable and then the variable is incremented by one.
var –
The result of the expression is the value of the variable and then the variable is decremented by one.
expr + expr
The result of the expression is the sum of the two expressions.
expr - expr
The result of the expression is the difference of the two expressions.
expr * expr
The result of the expression is the product of the two expressions.
expr / expr
The result of the expression is the quotient of the two expressions. The scale of the result is the value of the variable scale
expr % expr
The result of the expression is the “remainder” and it is computed in the following way. To compute a%b, first a/b is computed to scale
digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale
+scale(b) and scale(a). If scale
is set to zero and both expressions are integers this expression is the integer remainder function.
expr ^ expr
The result of the expression is the value of the first raised to the second. The second expression must be an integer. (If the second expression is not an integer, a warning is generated and the expression is truncated to get an integer value.) The scale of the result is scale
if the exponent is negative. If the exponent is positive the scale of the result is the minimum of the scale of the first expression times the value of the exponent and the maximum of scale
and the scale of the first expression. (e.g. scale(a^b) = min(scale(a)*b, max(scale
, scale(a))).) It should be noted that expr^0 will always return the value of 1.
( expr )
This alters the standard precedence to force the evaluation of the expression.
var = expr
The variable is assigned the value of the expression.
var = expr
This is equivalent to “var = var expr” with the exception that the “var” part is evaluated only once. This can make a difference if “var” > is an array.

比较符

>, <, <=, >=, ==, !=

语句

  • if语句:
    if ( expression ) { statement1 } [else { statement2 }]
  • while语句:
    while ( expression ) { statement }
  • for语句:
    for ( [expression1] ; [expression2] ; [expression3] ) { statement }
    所有循环语句里都支持continue和break

函数

define name ( parameters ) { newline
auto_list statement_list }
例如:

1
define d (n) { return (2*n); }

还有几个内置的函数用来计算三角函数, 这里我就不说了, 感兴趣就仔细看下manual中相应的部分.

我这里写一个非常简单的例子供参考:

1
2
3
4
5
6
7
8
define square (x) {
return x ^ 2;
}
a = 3
for (i=1; i<10; i++) {
a += 1
}
square(a)