Shell 技巧 - Solve: 命令行计算器重制版
哎呀!两个月前,我开始探索如何编写一个简单但非常有用的交互式命令行计算器作为 shell 脚本,并在专栏结尾写道:“下个月,我们将深入研究有用的改进,并使其成为我们 Linux 工具包的完整补充。下个月见!”
不幸的是,上个月,我被电影 The Number 23 分心,开始编写另一个脚本,研究如何在 shell 脚本环境中进行命理学。你可能会认为我是一个典型的程序员,被其他事情分心而忘记了原本的计划。这让我想起了 1990 年代末那些辉煌的创业时代,但这完全是另一个故事了。
无论如何,命理学可以再等一个月。本专栏,我想完成命令行计算器,因为,嗯,因为它非常有用,同时令人惊讶的是,这么多年来 Linux 中竟然没有一个像样的命令行计算器。我是认真的!
那已经是很久以前的事了,所以让我提醒您,给您提供基本计算器的简短脚本是这样的
#!/bin/sh bc << EOF scale=4 $@ quit EOF
就是这样。将其命名为 solve.sh,例如,您可以像这样测试它
$ sh solve.sh 1+3 4 $ sh solve.sh 11/7 1.5714
也很容易将 solve 别名设置为 shell 命令
alias solve="sh solve.sh"
或者,更好的是
alias solve="sh ~/bin/solve.sh"
因为无论您在文件系统中的哪个位置,这都有效(位置相关的命令是典型的 shell 错误)。
然而,我真正想要的是能够进入“solve”模式,在其中我输入的任何内容都自动被假定为数学方程式,而不是每次都必须输入solve每次。
我们过去讨论过 shell 脚本包装器,所以您应该还记得这个基本结构
while read userinput do echo "you entered $userinput" done
这还太粗糙,尚不能使用,但我们可以轻松添加一个提示符,使其看起来像一个真正的程序
echo -n "solve" while read expression do echo "you entered $expression" echo -n "solve: " done
看起来不错?实际上,并非如此。这里有一个细微的错误,这是另一个常见的脚本错误。问题在于 Linux 中有两个 echo 命令:一个是 shell 本身内置的功能,另一个是位于 /bin 中的单独命令。这很重要,因为内置的 echo 不知道 -n 标志的作用,但 /bin/echo 命令知道。稍作调整,我们就准备好测试了
/bin/echo -n "solve: " while read expression do echo "you entered $expression" /bin/echo -n "solve: " done
让我们看看会发生什么
solve: 1+1 you entered 1+1 solve: ^D
这更像样了。
然而,我们真正想要的是一个足够智能的脚本,可以识别您是否在命令行上指定了参数。如果您指定了,它会求解该方程式;如果您没有指定,它会将您置于交互模式。
通过测试 $# 变量,这出奇地容易实现,$# 变量指示传递给脚本的参数数量。想看看它是否大于零吗?这样做
if [ $# -gt 0 ] ; then
在向您展示完整脚本之前,还有一个改进:我希望在用户输入以下内容时退出quit或exit,而不是强迫他们输入^D以指示标准输入上的文件结束(这会导致 read 语句返回 false 并结束循环)。
这可以通过简单的字符串比较测试来完成,您应该还记得,字符串比较测试使用 =(-eq 测试用于数值)。因此,测试 $expression 以查看它是否为“quit”很容易
if [ $expression = "quit" ] ; then
为了使其更健壮,实际上最好在这里引用变量名,这样,如果用户输入空字符串(只需按回车键),条件测试就不会因丑陋的错误消息而失败
if [ "$expression" = "quit" ] ; then
因为我喜欢让我的脚本具有灵活性,所以我还添加了 exit 作为 quit 的替代方案,这很容易通过稍微复杂的条件测试来完成
if [ "$expression" = "quit" -o "$expression" = "exit" ] ; then
-o 是 shell 条件测试中的逻辑 OR 语句,但我感觉您已经明白了。
这就是脚本目前的状态,完整代码如下
#!/bin/sh if [ $# -gt 0 ] ; then bc << EOF scale=4 $@ quit EOF else /bin/echo -n "solve: " while read expression do if [ "$expression" = "quit" -o "$expression" = "exit" ] ; then exit 0 fi bc << EOF scale=4 $expression quit EOF /bin/echo -n "solve: " done echo "" echo "solved." fi exit 0
我想说,简洁且非常有用。如果我要继续改进它,接下来我会做的是编写一个简单的帮助页面,我会将其存储在某个库文件夹中,并在输入以下内容时显示?或help。它只会解释 bc 理解的表达式的语法(尽管由于我们是以迭代方式调用 bc,因此我们无法拥有持久变量等等,因此不幸的是,这种方法无法让我们访问二进制计算器的全部功能)。
要了解您可以输入哪种复杂的表达式,只需输入man bc。然后,让它成为您进一步调整和修改此脚本的灵感!
下个月,我将回到命理学脚本,看看我们能从看似良性的世界中确定哪些奇怪的事情。记住,仅仅因为我打乱了顺序,并不意味着我们不会来找你,亲爱的读者!
Dave Taylor 是一位拥有 26 年 UNIX 经验的资深人士,The Elm Mail System 的创建者,以及畅销书 Wicked Cool Shell Scripts 和 Teach Yourself Unix in 24 Hours 等 16 本技术书籍的作者。他的主要网站是 www.intuitive.com,他还通过 AskDaveTaylor.com 提供技术支持。