Linux 命令行交互式计算器

了解 Bash 脚本如何将终端变成强大的计算器。
505 位读者喜欢这篇文章。
Out of the trash and into the classroom

Opensource.com

如果您正在阅读本文,很有可能您不仅熟悉计算机系统上的命令行,而且非常习惯使用命令行来排除图形界面。我理解——自从命令行是计算世界中唯一的选择以来,我就一直在使用它,甚至在很久以前还为 BSD Unix 贡献了代码。现代 GUI 有很多优点,但在功能、速度和灵活性方面,命令行仍然很强大,如果您打字速度快,则更是如此。

然而,典型的 Unix 或 Linux 系统的命令行中缺少一些功能,尤其是一个强大而灵活的计算器。您可以使用 expr 甚至 shell $(( )) 表示法,但它们非常有限,当您尝试解决 10/3 或任何不是简单整数数学的问题时,这一点会立即显现出来。

您可以使用基本计算器 bc,但它使用的语言只有饱经风霜的老派黑客才可能喜欢,而且很难理解多年以后它在系统中的用途。bc 配备了笨拙的界面和明显缺乏有用的命令行选项,它仍然是操作系统的一部分,这真是一个谜。

幸运的是,我们谈论的是 Linux,这意味着我们可以通过在一个提供我们所需原始功能的工具周围包装一个更好的界面来解决问题——在 Linux 术语中,这是一个“包装程序”,原因显而易见。

这就是 Bash shell 脚本 calc 所做的——提供一个简单、用户友好的命令行计算器。它甚至具有有用的默认设置,因此您无需记住在解决 10/3 之前将十进制精度设置为非零。

使用 bc

bc 被称为任意精度二进制计算器,但奇怪的是,它的默认行为是在一个完全缺乏提示符的交互式 shell 中仅使用整数值。这是一个典型的交互

$ bc
1+1
2
10/3
3
quit

输入一个数学方程式,它会解决并显示结果。但是 10/3 仍然是 3?为了解决这个问题,bc 用户很快就熟悉了 scale,它允许您指定显示结果的精度;较高的 scale 值在小数点后提供更多位数。就像这样

10/3
3
scale=4
10/3
3.3333
scale=20
10/3
3.33333333333333333333
quit

这些信息确实足以了解如何生成一个简单的、命令行友好的浮点计算器作为 shell 脚本

#!/bin/sh
cat << EOF | bc
scale=2
$*
EOF
exit 0

这个想法很简单:无论用户将什么指定为命令的参数,都直接将其馈送到 bc,但首先将 scale 设置为 2。在实践中,它已经很有用了

$ calc '(100/3) * 2 + (11 + 333.5)'
411.16

还不错。但是,让我们把这个简单的想法变成一个交互式计算器 shell,您可以在其中打开一个窗口,并且任何时候遇到方程式,只需复制/粘贴它并快速解决它。

Calc:交互式计算器

上面的小 shell 脚本可以轻松地变成一个简单的函数,最终看起来像这样

scriptbc()
{
  scale=$1 ; shift

  cat << EOF | $bc
  scale=$scale
  $*
EOF
}

当在 shell 脚本中调用此函数时,您需要记住的是,第一个参数始终是所需的 scale 值,否则 bc 肯定会感到困惑。

但那是艰苦的工作。现在主循环出奇地简洁

while read command args 
do 
   case $command 
   in
      quit|exit) exit 0                      ;;
      help|\?)   show_help                   ;;
      scale)     scale=$args                 ;;
      *)  scriptbc $scale "$command" "$args" ;;
   esac 
   /bin/echo -n "calc> "
done

不太复杂,而且还添加了一个帮助函数。请注意 Bash shell 让您在 while 语句中使用 read 命令的巧妙方式——read 总是将用户键入的内容分解为每个列出的变量一个单词,其余所有内容都放在给定的最后一个变量中。因此,如果用户键入 1+1,则 read command args 表示 command="1+1",但如果用户键入 "1 + 1",则 command="1" 和 args="+ 1"。在这两种情况下,它都可以正常工作,当然,这是为了让用户也可以指定命令词。

一些额外的 echo 语句使事情变得漂亮,我们就得到了一个真正的、功能强大的交互式计算器,所有这些都由 bc 提供支持

$ calc
Calc--a simple calculator. Enter 'help' for help, 'quit' to quit.
calc> help
  In addition to standard math functions, calc also supports:
    a%b = remainder of a/b
    a^b = exponential: a raised to the b power
    s(x) = sine of x, x in radians
    c(x) = cosine of x, x in radians
    a(x) = arctangent of x, in radians
    l(x) = natural log of x
    e(x) = exponential log of raising e to the x
    j(n,x) = Bessel function of integer order n of x
    scale N = show N fractional digits (default = 2)
calc> s(1)
.84
calc> 100 + (10 * 3.55)
135.50
calc> 5545 + 11 – 4.55 
5551.45
calc> 10 / 3
3.33
calc> quit

尽管它的界面可能很奇怪,但事实证明 bc 还有其他绝招,包括用户设置和使用变量的能力,使其更像是一种数学编程语言。问题是,此脚本每次调用 bc 一次,因此无法在调用之间保留状态。这意味着,尽管用户可以输入诸如 cars=25 之类的语句,但如果他们在下一行引用该变量,它将从 bc 的内存中消失。

bc 有隐藏的超能力,但是……

bc 还支持各种编程结构,包括 ifwhilefor 语句、halts、breaks、continues 用于循环管理以及函数。但坦率地说:如果您真的想编写一个简洁的程序来解决数学方程式,那么有更好的选择,从 Perl 到大型、超级强大的工具,如 Matlab

尽管我非常欣赏功能蔓延背后的创造精神,但也应该认识到给定程序的局限性和功能,而不是花费数天时间使其更复杂,而是接受它可以解决某些——但不是所有——这个领域的问题。实际上,尽管 bc 支持函数、命令流和变量,但我怀疑您很难在现代 Unix 或 Linux 系统上找到一个利用此功能的脚本,并且可以将其从 bc 中剥离出来而没有人注意到。

对于直接的问题,快速、简单的解决方案一直是命令​​行界面的强大优势,也是 Unix 系统设计如此强大的原因。《Wicked Cool Shell Scripts 2nd Edition》这本书中,我的合著者和我非常详细地探讨了这个概念,提供了 100 多个 Bash shell 脚本来令人惊叹和愉悦。但从根本上说,无论您是在 Mac OS 命令行、Linux 系统还是旧式 Unix 服务器上,我们都在使用脚本在命令行这堵砖墙上添加一层新的砂浆。

如果您偶尔使用命令行,您会惊讶于我们的脚本集合(例如 calc)对您有多大帮助。毕竟,伟大的建筑是由小砖块和小抹刀的砂浆建造的,对吧?

标签
User profile image.
Dave Taylor (@DaveTaylor) 自 1980 年代以来一直参与 Unix 和 Linux,是 BSD 4.4 Unix 的贡献者,并编写了 Elm 邮件系统等程序。

14 条评论

不错!我是 bc 的粉丝,但我总是觉得它的语法有点难以理解,通常最终会使用 elisp 代替。`calc` 看起来很棒。现在就添加到 ~/bin!

还有,很高兴在这个网站上看到 Dave Taylor!我记得拿起我的第一本 Linux Journal 并惊叹地阅读 Dave 的专栏。很高兴看到他的作品在这里。

为了让事情更简单,我总是使用 `bc -l' 来代替打开 bc 然后设置 scale,它会自动将 scale 设置为 20!

我从老前辈那里学到的一个技巧...与其从 shell 将单行管道输入到 bc,更灵活的方法是使用“shebang”。(顺便说一句,这不仅适用于 bc,因此它本身就是一个非常有用的技术)。

创建一个如下所示的脚本。请注意第一行(“shebang”),它导致其余部分由 bc 命令而不是 shell (/bin/sh) 处理。这是一个非常简单的示例,它只设置了 scale 因子

#!/bin/bc
scale=10

将上述内容放在文件中(例如“bc10”),保存它,并使其可执行。当您运行它时,将执行 scale=10 命令,此后 bc 命令将在其正常的交互模式下运行。您现在可以使用 bc 的所有功能,包括设置变量,并在后续行中使用它们。

当然,这可以走得更远。“shebang”上可以添加其他命令行选项。例如,以下示例显示了如何打开 bc 中的数学库。

此外,您可以定义自己的函数,或进行一些谷歌搜索以找到许多方便的现有函数。按位运算、浮点等等。通过将它们放在您的脚本中,您可以在需要时随时调用它们。

#!/bin/bc --mathlib

scale=10

define double(x) {
return (2*x);
}

尽情享受吧!

您显然没有运行命令

$ bc --help

如果是这样,您会首先看到以下命令

$ bc -l (或 --mathlib)

我在我的 ~/.bash_aliases 中设置了一个别名,所以我只需要执行

$ bc

我就有了完整的浮点数学。bc 非常有用。我使用它没有问题。我曾经使用 HP RPN 计算器!试试处理那个吧!;^) 在这里试试

http://hp15c.com/([左键单击] 计算器图像)

至少 bc 知道如何正确计算“3+3*3”,并得到正确的结果“12”。Mickey$oft Windows 计算器应用程序希望它可以!他们的计算器应用程序结果为“18”!;^)

但它不是 RPN。:(

或者 Orpie,我猜。

如果您是 RPN 的粉丝,请尝试 `dc`。

回复 作者 Beelzebob (未验证)

好文章!
我一直在使用一个非常简单的别名,这是我从一位同事那里学到的。它在 Unix shell 中执行计算非常强大。
这个别名应该适用于几乎所有 Linux 系统,因为它们都安装了 Perl。

这是别名
alias = 'perl -e "print eval \!*;"; echo "" '

现在您可以在“=”号后键入非常复杂的计算。这是一个简单的例子
= 3/10 * sin(3.14/180*30) + 2.1**2.5
6.54062817586247

尽情享受吧 :-)

当我尝试将您的别名添加到 bashrc 时,我得到

bash: alias: =: 未找到

回复 作者 Haroon Showgan (未验证)

tcsh shell 支持此别名命令。我不使用 bash shell,但我确信它有一个等效的别名命令。

回复 作者 Derek (未验证)

我知道偏离了最初的重点,但我在我的 .bash_profile 中有这个...

alias calc='python -ic "from __future__ import division; import readline; readline.parse_and_bind(\"bind -v\") ; from math import * ; "'

readline 的东西只是为了获得 vim 风格的编辑。math 模块为您提供三角函数、pi、floor 等。

几年前我想出了一个不错的解决方案:一个脚本,它将命令行参数转换为 C++ 表达式,将其嵌入到 .cpp 临时文件中,编译它,运行它,然后删除它。
再强大和简单不过了 :)
shell-calc.googlecode.com

好文章,我只在脚本(ksh)中真正使用过 bc。

除非我只有终端访问权限,否则我没有看到直接使用它的需要。否则,我寻找的是一个不错的图形代数计算器。

一些脚本用法
将 IP 地址转换为用于比较的整数。类似于 inet_aton。
inp=10.11.12.13
oct1=`echo $inp | awk -F"." '{print $1}'`
oct2=`echo $inp | awk -F"." '{print $2}'`
oct3=`echo $inp | awk -F"." '{print $3}'`
oct4=`echo $inp | awk -F"." '{print $4}'`
NUM=`echo "scale=0; (256^3*$oct1) + (256^2*$oct2) + (256*$oct3) + ($oct4)" | bc -l`

将其转换回来
inp=168496141
oct1=`echo "scale=0; $inp/256^3%256" | bc -l`
oct2=`echo "scale=0; $inp/256^2%256" | bc -l`
oct3=`echo "scale=0; $inp/256%256" | bc -l`
oct4=`echo "scale=0; $inp%256" | bc -l`
IP=`echo "$oct1.$oct2.$oct3.$oct4"`

四舍五入:(调整值以检查结果)
adjust=30.9 ; nominal=12.23
adjusted=`echo "scale=10; ($adjust*2)*$nominal" | bc | xargs printf "%1.0f\n"`

bc 是一个非常强大且有价值的工具!

我对 bc 唯一真正的问题是默认设置(我通常使用 bc -l 来解决这些问题),并且内置函数可能比我希望的要少。因此,就此而言,calc 看起来并没有提供任何会促使我切换的东西。

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.