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 总是将用户输入的内容分解为每个列出的变量一个单词,其余所有内容都放在给定的最后一个变量中。所以 read command args 如果用户输入 1+1,则 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)对您有多大帮助。毕竟,伟大的建筑是由小砖块和小 trowels 的砂浆建造的,对吧?

标签
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.