算术运算

Shell允许在某些情况下对算术表达式进行求值,比如:let和declare 内置命令,(( ))复合命令和算术扩 展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 被困并标记为错误。运算符及其优先级,关 联性和值与C语言相同。以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。

注意:bash 只支持整数,不支持小数

* / % multiplication, division, remainder, %表示取模,即取余数,示例:9%4=1,5%3=2 + - addition, subtraction
i++ i-- variable post-increment and post-decrement
++i --i variable pre-increment and pre-decrement
= *= /= %= += -= <<= >>= &= ^= |= -+ unary minus and plus
!~ logical and bitwise negation ** exponentiation 乘方,即指数运算 << >> left and right bitwise shifts <= >= < > comparison
== != equality and inequality
& bitwise AND
| bitwise OR
^ bitwise exclusive OR
&& logical AND
|| logical OR
expr?expr:expr conditional operator
expr1 , expr2 comma

乘法符号有些场景中需要转义

实现算术运算的方法

(1) let var=算术运算表达式
(2) ((var=算术运算表达式)) 和上面等价
(3) var=$[算术运算表达式]
(4) var=$((算术运算表达式))
(5) var=$( expr arg1 arg2 arg3 ... ) # 注意两边的空格
(6) declare -i var = 数值
(7) echo '算术表达式' | bc

内建的随机数生成器变量:

$RANDOM 取值范围:0-32767

示例

# 生成 0 - 49 之间的随机数
[root@centos8 ~]#echo $[$RANDOM%50]
49 # 随机字体颜色
[root@centos8 ~]#echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m"
hello
[root@centos8 ~]#echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m"
hello
[root@centos8 ~]#echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m"
hello
[root@centos8 ~]#

增强型赋值:

+= i+=10    # 相当于 i=i+10
-= i-=j # 相当于 i=i-j
*=
/=
%=
++ i++ ++i # 相当于 i=i+1
-- i-- --i # 相当于 i=i-1

1. (())用法(常见且效率最高)

执行简单的整数运算,只需要将特定的算术表达式用"$(("和"))"括起来

shell的算术运算符号都置于"$((".........."))"语法中,这一语法如同上双引号功能,除了内嵌双引号无需转义

注意:

  • $() 代表包含的是系统命令

  • $(()) 代表包含的是数值运算

变量表达式定义:((a=1+2**3-4%3)) 或者 b=$((a=1+2**3-4%3))

[root@centos ~]#((a=1+2**3-4%3))
[root@centos ~]#echo $a
8
[root@centos ~]#b=$((a=1+2**3-4%3))
[root@centos ~]#echo $b
8
[root@centos ~]#echo $((1+2**3-4%3))
8
[root@centos ~]#
echo $((a+=1)) 相当于echo $((a=a+1))
echo $((3>2))
echo $((3<2))
echo $((100*(100+1)/2)) # 变量定义计算
myvar=99
echo $(($myvar + 1))
# 或者
myvar=$(( $myvar+1 ))
echo $myvar
[root@centos ~]#a=10
[root@centos ~]#echo $((a++)) # 先输出a自身的值,因为a为10,所以输出10
10
[root@centos ~]#echo $a # 上面输出a的值后,a自增1,所以a为11
11
[root@centos ~]#a=10
[root@centos ~]#echo $((++a))
11
[root@centos ~]#echo $a
11
[root@centos ~]# [root@centos ~]#a=10
[root@centos ~]#echo $((a--)) # 先输出a自身的值,因为a为10,所以输出10
10
[root@centos ~]#echo $a # 上面输出a的值后,a自减1,所以a为9
9
[root@centos ~]#a=10
[root@centos ~]#echo $((--a))
9
[root@centos ~]#echo $a
9
[root@centos ~]#

结论

echo $((a++))和echo $((a--))      # 表示先输出a自身的值,然后再进行++ --的运算
echo $((++a))和echo $((--a)) # 表示先进行++ -- 的运算,再输出a自身的值

变量在前,先输出变量值,变量在后,就是先运算后输出变量的值

命令行传参方式:

#/bin/bash
if [ $# -ne 2 ];then
echo "Usage:$0 NUM1 NUM2"
exit 1
fi
[ -n "$(echo $1|sed 's#[0-9]##g')" ] && {
echo "num1 must be int"
exit 1
}
[ -n "$(echo $2|sed 's#[0-9]##g')" ] && {
echo "num2 must be int"
exit 1
}
a=$1
b=$2
echo "a-b = $(( $a - $b ))"
echo "a+b = $(( $a + $b ))"
echo "a*b = $(( $a * $b ))"
echo "a/b = $(( $a / $b ))"
echo "a**b =$(( $a ** $b ))"
echo "a%b = $(( $a % $b ))"

简单实现一个加减乘除功能的计算器,通过命令行传参的方式实现

方法一: echo $(($1))
方法二: echo $(($1$2$3))

2. let赋值表达式

let赋值表达式功能等同于:((赋值表达式)),let命令尽量不用

[root@centos ~]#i=2
[root@centos ~]#let i=i+8
[root@centos ~]#echo $i
10
[root@centos ~]#
# 提示:let i=i+8等同于((i=i+8)),但后者效率更高

++i:先自加,再返回 i

#!/bin/bash
#
i=100
let j=++i # 此处先会返回 i=i+1 的值,即 i=100+1=101,然后再赋值给 j ,所以 j 也等于 101 echo $i # i=101
echo $j # j=i=101

i++:先返回 i ,再自加

#!/bin/bash
#
i=100
let j=i++ # 此处会先返回 i 的值,即 i=100,然后再赋值给 j ,所以 j 等于 100,最后再返回 i=i+1,即i=100+1=101,所以,此时 i=101 echo $j # j=100
echo $i # i=101

3. expr命令用法

expr命令一般用于整数值,但也可用于字符串,用来求表达式变量的值,同时expr也是一个手工命令行计算机

1、注意运算符和数字左右都有空格,否则不会运算

[@sjs_115_196 ~]# expr 11 + 1>/dev/null
expr: syntax error
[@sjs_115_196 ~]# echo $?
2
[@sjs_115_196 ~]# expr 11 + 1 >/dev/null
[@sjs_115_196 ~]# echo $?
0
[@sjs_115_196 ~]#

2、使用乘号时,必须用反斜线屏蔽其特定含义,因为shell可能会误解星号的含义

[root@centos ~]#expr 2 * 2
expr: syntax error: unexpected argument 'anaconda-ks.cfg'
[root@centos ~]#expr 2 \* 2
4
[root@centos ~]#

3、增量计算:

expr在循环中可用于增量计算,首先,循环初始化为0,然后循环加1,反引号的用法为命令替代

最基本的一种是从(expr)命令接受输出并将之放入循环变量

i=0
i=$(expr $i + 1)
echo $i

(2)expr $[$a+$b] 表达式形式:

expr $[2+3]
expr $[2*3]
expr $[2**3]
expr $[2/3]

(3) expr和变量的子串截取简单对比

expr length "I am songwanbo"
expr substr "I am songwanbo" 2 2
# 等同于
var="I am songwanbo"
echo ${#var} # 计算字符串的长度
echo ${var:2:2} # 从第2个开始取,取2个

示例:变量的处理,计算变量长度与其他不同方法的耗时对比

chars=`seq -s " " 100`
$ echo ${#chars} # 速度最快 $ echo $(expr length "$chars") 或者 expr length "$chars" $ echo ${chars}|wc -L time for i in $(seq 10000);do count=${#chars};done # 速度最快
time for i in $(seq 10000);do count=`expr length "$chars"`;done # 介于两者之间
time for i in $(seq 10000);do count=`echo ${chars}|wc -L`;done # 速度最慢

4. 其他

[root@centos8 ~]#echo $[2+3]
5
[root@centos8 ~]#echo $[ 2 * 3 ]
6
[root@centos8 ~]#typeset -i A=1 B=3
[root@centos8 ~]#A=A+B
[root@centos8 ~]#echo $A
4
[root@centos8 ~]#

5. bc是unix下的计算器,它可以用在命令行下面

i=2
i=`echo $i + 1|bc` 效率低
因为bc支持科学计算,所以这种方法功能非常强大
echo "touch file"
echo "touch file"|bash echo 1+1|bc
echo 3.5+5.6|bc
echo "5.23*3.32"|bc -l
echo "obase=2;8"|bc 将10进制8转换成2进制
echo "obase=16:20"|bc 将10进制20转换成16进制
echo "scale=6;5.23*3.12"|bc 结果取6位

计算1+2+3+...+100,用bc计算,拼接1+2+3+4+5+6+....100

# 方法1:
seq -s "+" 100|bc # -s 指定分隔符 # 方法2:
echo {1..100}|tr " " "+"|bc # 用tr做替换,把空格替换成+号 # for循环的写法:
#!/bin/bash
num=0
for i in `seq 100`
do
num=$(($num+$i))
done
echo $num # while循环的写法:
#!/bin/bash
num=0
i=0
while [ $i -le 100 ]
do
num=$(($num+$i))
i=$(($i+1))
done
echo $num

6. 示例

数值运算

# 方法一:declare
[root@centos ~]#x=111
[root@centos ~]#y=222
[root@centos ~]#declare -i z=$x+$y
[root@centos ~]#echo $z
333
[root@centos ~]# # 方法二:expr或let数值运算工具
[root@centos ~]#x=111
[root@centos ~]#y=222
[root@centos ~]#z=$(expr $x + $y) # 注意,+号左右两则必须有空格
[root@centos ~]#echo $z
333
[root@centos ~]# # 方法三:$((运算式)) 或 $[运算式]
[root@centos ~]#x=111
[root@centos ~]#y=222
[root@centos ~]#z=$(( $x + $y ))
[root@centos ~]#echo $z
333
[root@centos ~]#zz=$[ $x + $y ]
[root@centos ~]#echo $zz
333
[root@centos ~]#

虽然乘法和除法的优先级高于加法,但是通过小括号可以调整运算优先级

[root@centos ~]#sum=$(( (11+3)*3/2 ))
[root@centos ~]#echo $sum
21
[root@centos ~]#

14不能被3整除,余数是2

[root@centos ~]#s=$(( 14%3 ))
[root@centos ~]#echo $s
2
[root@centos ~]#

逻辑与运算只有相与的两边都是1,与的结果才是1,否则与的结果是0

[root@centos ~]#s=$(( 1 && 0 ))
[root@centos ~]#echo $s
0
[root@centos ~]#

范例:今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何?

鸡兔同笼,是中国古代著名典型趣题之一,记载于《孙子算经》之中。

[root@centos8 scripts]#cat chook_rabbit.sh
#!/bin/bash
#
HEAD=$1
FOOT=$2 RABBIT=$(((FOOT-HEAD-HEAD)/2))
CHOOK=$[HEAD-RABBIT]
echo RABBIT:$RABBIT
echo CHOOK:$CHOOK
[root@centos8 scripts]#./chook_rabbit.sh 30 80
RABBIT:10
CHOOK:20

逻辑运算

true, false

1,真
0,假 # 注意:以上为二进制

:&:和0相与结果为0,和1相与结果保留原值, 一假则假,全真才真

0 与 0 = 0
0 与 1 = 0
1 与 0 = 0
1 与 1 = 1

与逻辑

A B F
0 0 0
0 1 0
1 0 0
1 1 1

示例

[root@centos8 ~]#x=$[2&6]
[root@centos8 ~]#echo $x
2
[root@centos8 ~]#x=$[7&3]
[root@centos8 ~]#echo $x
3

:|:和1相或结果为1,和0相或结果保留原值,一真则真,全假才假


0 或 0 = 0
0 或 1 = 1
1 或 0 = 1
1 或 1 = 1

或逻辑

A B F
0 0 0
0 1 1
1 0 1
1 1 1

:!

! 1 = 0  ! true
! 0 = 1 ! false

非逻辑

A F
0 1
1 0

异或:^

异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得出另一个值Y

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

示例

[root@centos8 ~]#true
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#false
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#! true
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#! false
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

示例:变量互换

# 传统写法
[root@centos8 ~]#x=10;y=20;temp=$x;x=$y;y=$temp;echo x=$x,y=$y
x=20,y=10 # 异或写法
[root@centos8 ~]#x=10;y=20;x=$[x^y];y=$[x^y];x=$[x^y];echo x=$x,y=$y
x=20,y=10

短路运算

  • 短路与 &&
CMD1 短路与 CMD2

第一个CMD1结果为真 (1),第二个CMD2必须要参与运算,才能得到最终的结果
第一个CMD1结果为假 (0),总的结果必定为0,因此不需要执行CMD2
  • 短路或 ||
CMD1 短路或 CMD2
第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,才能得到最终的结果

shell算数和逻辑运算的更多相关文章

  1. shell算数运算

    ((i=$j+$k))    等价于 i=`expr $j + $k`((i=$j-$k))     等价于   i=`expr $j -$k`((i=$j*$k))     等价于   i=`exp ...

  2. 【Shell脚本学习10】Shell运算符:Shell算数运算符、关系运算符、布尔运算符、字符串运算符等

    Bash 支持很多运算符,包括算数运算符.关系运算符.布尔运算符.字符串运算符和文件测试运算符. 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最 ...

  3. JavaScript的语法、数据类型、基本算数和逻辑运算操作

    str.toString() 可以把字符串.数值.布尔值.对象转为字符串 String(str) 任何数值强制转换为字符串类型 <!DOCTYPE html> <html lang= ...

  4. Linux - Shell - 算数表达式 - 关系运算

    概述 shell 中基于 $(()) 的 关系运算 背景 复习 shell 脚本 凑数吧 准备 环境 os centos7 1. 位运算 代码 #!/bin/bash # 关系运算符 # 结果是 真/ ...

  5. Linux - Shell - 算数表达式 - 位运算

    概述 shell 中基于 $(()) 的 位运算 背景 复习 shell 脚本 凑数吧 准备 环境 os centos7 1. 位运算 代码 #!/bin/bash # 位运算 arg1=2 arg2 ...

  6. Shell运算符:Shell算数运算符、关系运算符、布尔运算符、字符串运算符等

    摘自:http://c.biancheng.net/cpp/view/2736.html

  7. python算数、逻辑运算,位运算

    算术运算符 对变量和数组进行算术运算. 算术运算符:+,-,*,/,% +:将连个或者多个数值相加 -:将两个数值相减 *:将两个数值相乘 /:将两个数值相除 %:取相除的余数 赋值运算符 将右边的值 ...

  8. Shell编程菜鸟基础入门笔记

    Shell编程基础入门     1.shell格式:例 shell脚本开发习惯 1.指定解释器 #!/bin/bash 2.脚本开头加版权等信息如:#DATE:时间,#author(作者)#mail: ...

  9. linux shell基础语法

    1.第一个Shell脚本 打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell 脚本,扩展名就用php好了. 输入一些代码 ...

随机推荐

  1. react new features 2020

    react new features 2020 https://insights.stackoverflow.com/survey/2019#technology-_-web-frameworks h ...

  2. how to watch vuex state update

    how to watch vuex state update watch https://vuex.vuejs.org/api/#watch https://vuex.vuejs.org/guide/ ...

  3. Spring 中的 MetaData 接口

    什么是元数据(MetaData) 先直接贴一个英文解释: Metadata is simply data about data. It means it is a description and co ...

  4. 【Android初级】如何实现一个有动画效果的自定义下拉菜单

    我们在购物APP里面设置收货地址时,都会有让我们选择省份及城市的下拉菜单项.今天我将使用Android原生的 Spinner 控件来实现一个自定义的下拉菜单功能,并配上一个透明渐变动画效果. 要实现的 ...

  5. Python数据结构与算法_最长公共前缀(05)

    编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...

  6. Vuex入门、同步异步存取值进阶版

    关注公众号查看原文: 1. vueX介&绍安装 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方 ...

  7. java 阿里云短信发送

    记录自己的足迹,学习的路很长,一直在走着呢~ 第一步登录阿里云的控制台,找到此处: 点击之后就到此页面,如果发现账号有异常或者泄露什么,可以禁用或者删除  AccessKey: 此处方便测试,所以就新 ...

  8. 创建AD域之后设置DNS服务访问外网

    AD域内需要有DNS服务器,用于解析域内的计算机名,域内的计算解析公网的域名需要设置一个转发器(Forwarder). 一定要设置好自己的默认网关.DNS因为部署在AD服务器上,直接loopback地 ...

  9. Linux系统编程【4】——文件系统

    pwd命令的作用 Linux的文件系统比较庞大,所以笔者从pwd这一命令入手,在实现的过程中加深对文件系统的了解. 输入:man pwd 从指导文档中可以看到,pwd命令的作用是显示出当前所处位置,以 ...

  10. docker ssh秘钥免密登录

    一.概述 有一台跳板机,已经实现了免密登录后端服务器.但是我写了一个django项目,它是运行在容器中的,也需要免密登录后端服务器. 虽然可以在容器中手动做一下免密登录,但是容器重启之后,之前做的设置 ...