• 一步步打造自己的linux命令行计算器


    相信很多人,在工作中会需要使用到计算器。一般的做法是,打开并使用系统自带的计算器。

    这种做法可能对我来说,有如下几个问题。

    • 太慢。每次需要打开计算器,然后改成编程模式,手工选择进制,再使用输入表达式进行计算。

    • 需要切换窗口。编程时经常是在终端中,使用GUI计算器则意味着要离开终端,计算完毕再切换回来。

    • 无法使用混合进制表达式。混合进制的意思是,在一个表达式中同时使用多种进制,如“0x10 * 10”表示十六进制的0x10乘以十进制的10。

    如果以上有一条你也有同感的话,那么你也应该试一下,使用命令行计算器。

    命令行计算器,调用bc

    只需经过简单的搜索,便可以了解到,linux中原生提供了一个命令行计算器 GNU bc。

    GNU bc支持高精度数字和多种数值类型(例如二进制、十进制、十六进制)的输入输出。

    bc的交互式使用方式,运行bc,进入交互模式。在交互模式中输入表达式,回车即可获得结果。需要退出时输入quit退出即可。

    bc的非交互式使用方式,通过管道将表达式传入。

    使用效果如下

    zhuangqiubin@zhuangqiubin-PC:~$ bc
    bc 1.07.1
    Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
    This is free software with ABSOLUTELY NO WARRANTY.
    For details type `warranty'. 
    1+2
    3
    quit
    zhuangqiubin@zhuangqiubin-PC:~$ echo "1+2" | bc
    3
    

    OK,get到了命令行计算器的新技能了,但每次进入交互模式或者手工输入“echo 表达式 | bc ”都感觉略麻烦。那这个时候,就需要脚本,写个mycalc.sh好了

    zhuangqiubin@zhuangqiubin-PC:~$ cat mycalc.sh
    #!/bin/bash
    
    echo "$@" | bc
    zhuangqiubin@zhuangqiubin-PC:~$ ./mycalc.sh 1+2
    3
    

    再把mycalc.sh拷贝到可访问的目录下,如

    sudo mv mycalc.sh /usr/bin
    

    对于没有sudo权限的情况,那也可以变通下

    mkdir -p ~/usr/bin
    
    mv mycalc.sh ~/usr/bin
    
    echo 'export PATH=$HOME/usr/bin:$PATH' >> ~/.bashrc
    
    source ~/.bashrc
    

    再alias一个顺手的命令名,比如拼音jisuan

     echo "alias jisuan='mycalc.sh'" >> ~/.bashrc
    

    更多bc的用法,可以通过man bc查看,网上也有许多介绍资料。

    解决进制问题

    bc仍然需要手工指定进制,在表达式前,使用ibase参数和obase参数指定输入输出的进制。并且不支持混合进制,因为ibase每次只能指定一种进制。

    zhuangqiubin@zhuangqiubin-PC:~$ echo "10+10" | bc
    20
    zhuangqiubin@zhuangqiubin-PC:~$ echo "ibase=16;10+10" | bc
    32
    

    但我们既然已经有了一个包装脚本mycalc.sh,那是不是可以把进制转换的工作交给它呢,当然可以。

    我们可以让mycalc.sh先处理下表达式中的数字,约定0x开头为十六进制,不带前缀为十进制,0o开头为八进制,0b开头为二进制。

    mycalc先将所有参数转换成统一的进制,如十进制,然后计算表达式的值,最终将结果再以多种进制的形式输出。这样我们就不同手工处理进制问题了。

    至于输出,为了方便起见,可以多种进制一起输出,需要哪个用哪个即可

    这里就不贴代码了,有兴趣可移步github https://github.com/zqb-all/smartbc,我们接着往下看,后面有更简单的方式。

    使用示例

    zhuangqiubin@zhuangqiubin-PC:~$ type jisuan
    jisuan 是 `~/mywork/mygithub/smartbc/smartbc' 的别名
    zhuangqiubin@zhuangqiubin-PC:~$ jisuan 10+10
    Original EQUATION: 10+10 
    Decimal  EQUATION: 10+10
    base2 : 10100
    base8 : 24
    base10: 20
    base16: 14
    zhuangqiubin@zhuangqiubin-PC:~$ jisuan 10+0x10
    Original EQUATION: 10+0x10 
    Decimal  EQUATION: 10+16
    base2 : 11010
    base8 : 32
    base10: 26
    base16: 1A
    

    更好的实现,使用python

    以上基于bc的计算器,已经可以满足我的需求了,也使用了一段时间。但其实还有更好的实现方式,使用python。

    在命令行中,输入python,进入交互模式,即可像bc一样执行表达式,得到结果。更棒的是,原生支持混合进制,不需要自己写代码预处理表达式了。简单可靠。

    代码及使用示例

    zhuangqiubin@zhuangqiubin-PC:~$ type jisuan
    jisuan 是 `~/.pycalc.py' 的别名
    zhuangqiubin@zhuangqiubin-PC:~$ cat ~/.pycalc.py 
    #!/usr/bin/env python2
    
    import sys
    
    equation=sys.argv[1]
    result=eval(equation)
    if isinstance(result, (float)):
        print "Attention:only base10 is float, others change to int before type"
    print "equation:",sys.argv[1]
    print "base2 : ",str(bin(int(result)))
    print "base8 : ",str(oct(int(result)))
    print "base10: ",str((result))
    print "base16: ",str(hex(int(result)))
    zhuangqiubin@zhuangqiubin-PC:~$ jisuan 10+10
    equation: 10+10
    base2 :  0b10100
    base8 :  024
    base10:  20
    base16:  0x14
    zhuangqiubin@zhuangqiubin-PC:~$ jisuan 10+0x10
    equation: 10+0x10
    base2 :  0b11010
    base8 :  032
    base10:  26
    base16:  0x1a
    

    更多输出格式

    一般,输出十六进制,十进制,二进制三种结果就足够用了。但如果有特殊需求,也可自己拓展。

    比如,当需要核对寄存器,检查某个bit时,一个个去数二进制的第19位,是很费眼睛的一件事。

    这个时候就需要更加直观的输出,可以一眼看到某个bit是0还是1。

    那好办,给二进制加上下标好了。如下

    代码

    #!/usr/bin/env python2
    
    import sys
    
    def formatBinString(num):
        result='bit:   '
        result_index='index: '
        num_len=len(num)
        if num_len > 32:
            return ""
        for i in num:
            num_len-=1
            result+=i
            result+=' | '
            result_index+=str(num_len).zfill(2)
            result_index+='| '
        return result+'
    '+result_index
    
    equation=sys.argv[1]
    result=eval(equation)
    if isinstance(result, (float)):
        print "Attention:only base10 is float, others change to int before type"
    
    print "equation:",sys.argv[1]
    print ""
    
    print "base2 : ",str(bin(int(result)))
    print "base8 : ",str(oct(int(result)))
    print "base10: ",str((result))
    print "base16: ",str(hex(int(result)))
    
    print ""
    print formatBinString(str(bin(int(result))[2:].zfill(32)))
    

    效果

    zhuangqiubin@zhuangqiubin-PC:~$ jisuan 10+0x10
    equation: 10+0x10
    
    base2 :  0b11010
    base8 :  032
    base10:  26
    base16:  0x1a
    
    bit:   0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 
    index: 31| 30| 29| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 09| 08| 07| 06| 05| 04| 03| 02| 01| 00|
    

  • 相关阅读:
    设置文本框的 placeholder 的颜色
    CSS单行文字超出省略
    【持续跟新】剑指Offer_Java实现
    Android必修课-Activity生命周期
    如何查看Android的jks签名的MD5
    Flutter 文字边框/边框颜色
    Flutter initState 初始化调用 Provide报错
    flutter 系统通知栏Demo 基于flutter_local_notifications: ^1.4.1
    # Flutter学习笔记(一)
    一个技术人毕业到就业的思考
  • 原文地址:https://www.cnblogs.com/zqb-all/p/9763219.html
Copyright © 2020-2023  润新知