shell数值运算

常见的运算

expr

下面列出了expr命令的基本用法,该命令只支持整数运算,不支持浮点运算,如下:

#加减乘除
expr 1 + 1
expr 3 - 1
expr 2 \* 6		#*通配符需转义
expr 10 / 5
#使用变量
a=10
expr $a / 2
#若不指定运算符,expr也可当作echo使用

$(())

该方法也可进行数值运算,与expr一样,不支持浮点数运算,在语法上不需要在运算符处加空格且运算效率最高

#计算45加80
echo $((45+80))
#计算a加b
a=72
b=725
echo $((a+b))
#上面的写法可省略$符号,但尽量加上,省得出错

$[]

依然是整数运算得一种方法,同上依然不支持浮点数运算

#计算626除以3
echo $[626/3]
#计算a加b
a=72
b=725
echo $[a+b]

let *

let也是整数运算的一种方法,不支持浮点数运算,与上面的不同,它支持C语言家族风格的++--写法

#求和
a=20
b=40
let sum=a+b
echo $sum
#自增
let i++
echo $i
#自减
let j--
echo $j
#加并赋值
let i+=88
echo $i

bc *

bc可通过管道进行数值计算,要求是前者输出必须是正确的表达式,可进行简单的浮点数运算(不是很好用)

#计算200加329
echo "200+329" | bc
#计算288.3452加339.24
echo "288.3452+339.24" | bc

AWK *

awkLinux/UNIX下非常牛逼的文本处理工具,甚至可以说是一门编程语言都不为过,当然做数学运算的能力也不在话下,包括完善的浮点数运算

#加
awk 'BEGIN{print 390+400}'
#减
awk 'BEGIN{print 500-240}'
#乘
awk 'BEGIN{print 25*29}'
#除
awk 'BEGIN{print 45/2}'
#幂
awk 'BEGIN{print 34^20}'
#通过管道获取参数
echo "230 21" | awk '{print $1*$2}'

Python *

利用Python解析器,我们也可以实现数值得运算需求

[root@shell ~]# python
Python 2.7.5 (default, Oct 30 2018, 23:45:53) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 34*45
1530
>>> 34/45
0
>>> 34/45.0
0.7555555555555555
>>> 34+45
79
>>> 34-45
-11

条件表达式

条件表达式也叫test,具有两种写法,可以进行各种判断,返回不同的值;test分为命令写法和方括号写法,其中方括号写法最为常用,如下代码都是可以执行成功的:

#命令写法,
test -f /etc/fstab && echo "存在该文件" || echo "该文件不存在"
#方括号写法
[ -f /etc/fstab ] && echo "存在该文件" || echo "该文件不存在"

判断 *

选项参数描述
!表达式取反!号后面表达式的返回值
-a表达式连接两个或多个表达式,当两个表达式都成立时返回0
-b指定一个block块设备文件判断block设备文件是否存在,存在返回0
-c指定一个character字符设备文件判断character设备文件是否存在,存在返回0
-d跟随一个目录名或目录的路径判断目录是否存在,存在返回0,否则返回非零
-e指定一个文件名或完整路径判断文件是否存在,如果存在返回0,所有类型文件
-f跟随一个文件名或文件路径及文件名判断文件是否存在,如果存在返回0,仅限于普通文件
-g指定一个文件名或完整路径判断文件是否存在SGID权限位
-G指定一个文件名或完整路径判断文件属组是否为当前用户属组
-h符号链接文件判断一个软链接是否存在
-k指定一个文件名或完整路径判断文件是否设置了粘滞位SBIT
-L符号链接文件判断一个软链接是否存在
-n字符串如果字符串不为空则返回0
-o表达式连接两个或多个表达式,任意表达式成立,就返回0
-O指定一个文件名或完整路径判断文件是否存在且属主为当前用户
-p指定一个管道文件的位置判断是否存在该管道文件
-r指定一个文件名或完整路径判断文件是否存在且具备读权限
-s指定一个文件名或完整路径判断文件是否存在且大小大于零,空文件返回1
-S指定一个套接字文件的位置判断套接字文件是否存在
-t指定一个文件描述符判断文件是否已被打开
-u指定一个文件名或完整路径判断文件是否被设置了SUID权限位
-w指定一个文件名或完整路径判断文件是否存在且具备写权限
-x指定一个文件名或完整路径判断文件是否存在且具备执行权限
-z字符串如果字符串为空则返回0

比较 *

选项参数描述
=str1 = str2比较两个字符串是否相等,相等返回0
!=str1 != str2比较两个字符串是否不同,不同返回0
-eqint1 -eq int2比较两个整数是否相等,相等返回0
-geint1 -ge int2比较int1是否大于或等于int2,满足任意条件返回0
-gtint1 -gt int2比较int1是否大于int2,满足条件返回0
-leint1 -le int2比较int1是否小于或等于int2,满足任意条件返回0
-ltint1 -lt int2比较int1是否小于int2,满足条件返回0
-neint1 -ne int2比较int1是否不等于int2,满足条件返回0
-effile1 -ef file2比较file2file2是否具有相同的设备号和inode
-ntfile1 -nt file2比较文件的修改时间,检测file1是否比file2
-otfile1 -nt file2比较文件的修改时间,检测file1是否比file2

语法

在写表达式时,必须严格注意格式,如下:

整数比较
#方括号与变量间需要有空格
[ $1 -eq $2 ]
#比较符必须与变量间有空格
字符串比较
#字符串不能使用-eq等进行比较,字符串使用=号,如果直接比较字符串需要使用双引号括起
[ $str1 = "ok" ]
#判断是否为空字符串
[ -n $str1 ]
文件比较及判断
#判断普通文件是否存在
[ -f /etc/hostname ]
#判断所有类型文件是否存在,忽略类型,判断套接字管道FD字符设备块设备都行
[ -e /dev/tty1 ]
#判断目录是否存在
[ -d /dev/pts ]
#判断文件是否为空文件
[ -s /root/.bashrc ]
取反结果
#在表达式前加上叹号可取反该表达式的返回值
[ ! -f /etc/hostname ]
#如果存在该文件正常情况下返回0,取反后返回值非零
多表达式与
#如果需要进行多条件匹配则可以使用-a参数连接两个或多个表达式
#只有两个表达式都成立结果才为0,否则返回非零
[ -f /etc/hostname -a -f /etc/fstab ]
多表达式或
#当两个或多个条件做判断时,如果需要任何表达式返回0整个表达式就为0的话需要使用-o
[ -f /etc/hostname -o -f /root/test.txt ]
正则匹配
#可以使用正则匹配来进行更细致的字符串过滤操作,使用时需要使用双[[]]包起
#判断输入内容是否为整数
read -p "Enter a number: " num
[[ $num =~ ^[0-9]+$ ]] && echo "输入的为整数: $num" || echo "输入了非整数! $num"
#=~表示正则匹配
#^以什么开头
#[0-9]所有数字范围
#+前边的字符可以出现多次
#$以什么结尾

一些常见的小玩意:

  1. ps aux中的VSZ列,并将结果相加

    #首先awk取列,然后tr将每行行尾换行替换为+,然后使用sed后向引用在末尾添加0并回车,最后交给bc计算
    ps aux | awk 'NR>2 {print $5}' | tr "\n" "+" | sed -r 's#(.*)#\10\n#g' | bc
    
  2. 实现一个简易计算器,循环执行,ctrl+c退出

    #!/bin/bash
    while true; do
            read -p "请输入第一个数字: " var1
            read -p "请输入第二个数字: " var2
            echo "$var1+$var2=$[$var1+$var2]"
            echo "$var1-$var2=$[$var1-$var2]"
            echo "$var1*$var2=$[$var1*$var2]"
            echo "$var1/$var2=$[$var1/$var2]"
            echo "按下Ctrl+c键可退出..."
            done
    
  3. 使用expr进行判断输入的是否为整数:

    #!/bin/bash
    #expr执行非整数运算会报错,此时返回非零值,检测此值
    read -p "请输入一个整数: " var
    expr $var + 0 > /dev/null 2>&1			#丢弃所有输出
    [ $? -ne 0 ] && echo -e "\033[31m参数不是整数! $var\033[0m" || echo -e "\033[32m输入的是整数: $var\033[0m"
    
  4. 调用系统函数库,更直观的输出

    #以下内容可以以交互模式执行,也可写入脚本执行
    #检查是否存在系统函数库文件,如果存在,导入到当前环境
    [ -f /etc/init.d/functions ] && . /etc/init.d/functions
    #使用action
    action "测试信息显示" /bin/true
    action "测试失败显示" /bin/false
    

    如下效果:

    shell_function_action

  5. 使用脚本显示系统基本信息,顺便来了点颜色

    #!/bin/bash
    #file: os_info.sh
    eth0_ip_addr=$(ifconfig eth0 | awk '/inet / {print $2}')
    eth1_ip_addr=$(ifconfig eth1 | awk '/inet / {print $2}')
    arch=$(hostnamectl | awk '/Virtual.*:/ {print $2}')
    os_ver=$(hostnamectl | awk '/Oper.*:/ {print $3,$4,$5,$6}')
    pub_ip_addr=$(curl -s http://cip.cc |awk '/IP/ {print $NF}')
    disk_use_info=$(df | awk '/\/$/ {print $(NF-1)}')
    
    echo -e "\033[32m当前系统的主机名是: $HOSTNAME\033[0m
    \033[33m当前系统的IP地址是: ETH0-> $eth0_ip_addr ETH1-> $eth1_ip_addr\033[0m
    \033[34m当前系统平台信息: $arch\033[0m
    \033[35m当前系统版本: $os_ver\033[0m
    \033[36m当前网络的出口公网IP: $pub_ip_addr\033[0m
    \033[37m当前系统的磁盘使用率: $disk_use_info\033[0m"
    

注: 可以将其加入rc.d下,每次登陆自动输出系统的基本信息。

  1. 多线程执行脚本,检查局域网IP占用情况

    #!/bin/sh
    

#Ping网段内所有的IP地址,检查有哪些IP正在被使用中 #其实没那么准确,PING通的前提是对方鸟你,如果你给对方发包,对方屌都不屌你(防火墙DROP情况下),照样PING不通,但IP地址还是处于占用的 [ -f /etc/init.d/functions ] && . /etc/init.d/functions for i in seq 254; do { IP=10.0.0.$i ping -c 1 -W 1 $IP >/dev/null 2>&1 [ $? -eq 0 ] && action "ping $IP is" /bin/true } & done


# shell  bash 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×