Bash: 如何计算一个数学表达式?

53
echo 3+3

我该如何在Bash中评估这样的表达式,以便得到6?

9个回答

110
echo $(( 3+3 ))

37

expr 是标准方法,但它只能处理整数。

bash 有一些扩展,但它们也只能处理整数:

$((3+3))  returns 6
((3+3))   used in conditionals, returns 0 for true (non-zero) and 1 for false
let 3+3   same as (( ))

let(( )) 可以用于赋值,例如:

let a=3+3
((a=3+3))

对于浮点数,你可以使用 bc

echo 3+3 | bc


expr 不仅可以处理整数,也可以处理其他类型的数据。例如,表达式 expr ( "0.5" < 20 ) 可以直接用作 if 条件语句。 - zw963
$(( ))expr 一样标准,自从早在90年代初期的 POSIX.2 中就已经被指定,并且执行速度更快。相比之下,let 只是为了向后兼容1980年代的 ksh 而存在于 bash 中。(与此相反,没有前导 $(( )) 是 bash 的扩展功能)。 - Charles Duffy
@zw963,POSIX并不要求expr支持除整数以外的任何内容。请参见https://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html -- 你的expr副本提供的任何浮点支持都是非标准扩展。 - Charles Duffy

24
在像zsh/ksh这样的shell中,您可以使用浮点数进行数学运算。如果需要更多的数学计算能力,可以使用像 bc/awk/dc 这样的工具。

例如:


```bash $ echo "scale=2; 3.14 * 2" | bc 6.28 ```
var=$(echo "scale=2;3.4+43.1" | bc)
var=$(awk 'BEGIN{print 3.4*43.1}')

看一下您正在尝试做什么

awk '{printf "%.2f\n",$0/59.5}' ball_dropping_times >bull_velocities

有没有关于 AWk 的注释符号的想法?如果我想要为我的测量结果明确指定格式怎么办?仅读取列可能会让人感到困惑。 - hhh
我不明白。请在你的问题中举例说明你的意思。 - ghostdog74
POP - 管道的威力!| bc 获得了我的个人认可。 - Sridhar Sarnobat
OP特别询问了关于Bash的问题。 - monzie

11
你可以使用 expr 命令,例如:
expr 3 + 3

要将结果存储到变量中,可以这样做:

sum=$(expr 3 + 3)
或者
sum=`expr 3 + 3`

由于本篇文章显然是给Unix初学者写的,我想补充一下:最后一行中的反引号是为了让shell在分配sum之前计算“epr 3 + 3”。 - Mark Peschel
expr是20世纪70年代的产物。自从POSIX.2在90年代初出版以来,shell就必须支持sum=$((3 + 3)),这更加高效。 - Charles Duffy

3

有很多种方法 - 最便携的方法是使用expr命令:

expr 3 + 3

2

我认为((3+3))方法是最快的,因为它由shell解释而不是外部二进制文件。使用所有建议的方法来计时一个大循环以获得最高效率。


*nix进程的设计旨在极度轻量化和快速,正是出于这个原因。因此,在常见用法的整体脚本性能方面考虑,使用外部二进制文件并不会真正变慢。 - hellodanylo
@hellodanylo,这仍然是数量级的差别。在UNIX上使用fork()+execve()比在Windows上更便宜,但仍然比在已经运行的进程中执行操作要慢得多。人们轻易地执行昂贵的操作,这是“整体脚本性能”被普遍认为速度不可接受的原因之一。 - Charles Duffy

1

感谢Dennis的帮助,以下是BC使用的示例:

$ cat calc_velo.sh

#!/bin/bash

for i in `cat ball_dropping_times`
do
echo "scale=20; $i / 59.5" | bc 
done > ball_velocities

把这个放进你的问题里。另外,你可以只使用一个awk命令。它可以解析文件,并处理小数计算。请查看我的答案。 - ghostdog74
1
你正在使用重定向运算符 >,它会每次截断(覆盖)目标文件。将其更改为追加运算符 >> 或将重定向放在 done 之后而不是 bc 之后,像这样:done > ball_velocities - Dennis Williamson

1

在这方面可能有用的一个用例是,如果你的操作数本身是一个bash命令,那么尝试这个。

echo $(( `date +%s\`+10 )) 或者甚至是 echo $(( `date +%s\`+(60*60) ))

在我的情况下,我正在尝试获取比当前时间晚10秒和1小时的Unix时间。


0

我对数学处理的理解涉及浮点处理。

使用bashjhttps://sourceforge.net/projects/bashj/),您可以简单地调用一个带有浮点处理、cos()、sin()、log()、exp()等的Java方法。

bashj +eval "3+3"
bashj +eval "3.5*5.5"

或者在bash脚本中,Java调用如下:

#!/usr/bin/bashj
EXPR="3.0*6.0"
echo $EXPR "=" u.doubleEval($EXPR)

FUNCTIONX="3*x*x+cos(x)+1"
X=3.0
FX=u.doubleEval($FUNCTIONX,$X)
echo "x="$X " => f(x)=" $FUNCTIONX "=" $FX

请注意速度:每次调用约为10毫秒(答案由JVM服务器提供)。
还要注意,u.doubleEval(1/2)将提供0.5(浮点数),而不是0(整数)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接