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 语句、停止、中断、循环管理的 continue 和函数。但让我们坦诚地说:如果您真的想编写一个简洁的程序来解决数学方程式,那么有更好的选择,从 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.