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 中仅使用整数值,而该 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 看起来并没有提供任何可以激励我切换的东西。

© . All rights reserved.