如果您正在阅读本文,很有可能您不仅熟悉计算机系统上的命令行,而且非常习惯使用命令行来排除图形界面。我理解——自从命令行是计算世界中唯一的选择以来,我就一直在使用它,甚至在很久以前还为 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 还支持各种编程结构,包括 if
、while
和 for
语句、halts、breaks、continues 用于循环管理以及函数。但坦率地说:如果您真的想编写一个简洁的程序来解决数学方程式,那么有更好的选择,从 Perl 到大型、超级强大的工具,如 Matlab。
尽管我非常欣赏功能蔓延背后的创造精神,但也应该认识到给定程序的局限性和功能,而不是花费数天时间使其更复杂,而是接受它可以解决某些——但不是所有——这个领域的问题。实际上,尽管 bc 支持函数、命令流和变量,但我怀疑您很难在现代 Unix 或 Linux 系统上找到一个利用此功能的脚本,并且可以将其从 bc 中剥离出来而没有人注意到。
对于直接的问题,快速、简单的解决方案一直是命令行界面的强大优势,也是 Unix 系统设计如此强大的原因。《Wicked Cool Shell Scripts 2nd Edition》这本书中,我的合著者和我非常详细地探讨了这个概念,提供了 100 多个 Bash shell 脚本来令人惊叹和愉悦。但从根本上说,无论您是在 Mac OS 命令行、Linux 系统还是旧式 Unix 服务器上,我们都在使用脚本在命令行这堵砖墙上添加一层新的砂浆。
如果您偶尔使用命令行,您会惊讶于我们的脚本集合(例如 calc)对您有多大帮助。毕竟,伟大的建筑是由小砖块和小抹刀的砂浆建造的,对吧?
14 条评论