Shell编程之运算符

本文主要对Shell中的运算符进行简单总结,另外本文所使用的Linux环境为CentOS Linux release 8.1.1911,所使用的Shell为bash 4.4.19(1)-release

一、算术运算符

运算符说明示例
+单目正号((+3))结果为3
-单目负号((-3))结果为-3
++自增(变量前,先运算后取值;变量后,先取值后运算)b=2((a=++b))后a为3,b为3;((a=b++))后a为2,b为3
自减(变量前,先运算后取值;变量后,先取值后运算)b=2((a=--b))后a为1,b为1;((a=b--))后a为2,b为1
+expr 3 + 2结果为5
-expr 3 - 2结果为1
*expr 3 \* 2结果为6
/expr 3 / 2结果为1
%取模expr 3 % 2结果为1
**幂运算((3**2))结果为9

expr可用于整数运算,也可以处理字符串,使用expr进行运算时,表达式和运算符之间必须加空格,乘号*和小括号()前要加\转义(小括号是左右括号前都要加\转义)。
(( expression ))会对算术表达式求值,如果表达式的值不是0,则返回状态是0,否则返回状态是1,这和let "expression"等价。
(( ))前面加上$符号可以获取(( ))命令的执行结果,即整个表达式的值。
(( ))只能进行整数运算,不能对浮点数或字符串进行运算。

示例如下:

#!/bin/bash

# 单目正负号
echo "单目正负号"
a=3
echo $((+a)) $((-a))

# 自增自减运算
echo "自增自减运算"
b=2
echo "b:${b}"
((a=++b))
echo "a=++b : a:${a},b:${b}"
b=2
((a=b++))
echo "a=b++ : a:${a},b:${b}"
b=2
((a=--b))
echo "a=--b : a:${a},b:${b}"
b=2
((a=b--))
echo "a=b-- : a:${a},b:${b}"

# 加减乘除、取模、幂运算
echo "加减乘除、取模、幂运算"
a=3
b=2
echo "a:${a},b:${b}"
echo "a + b : `expr ${a} + ${b}`"
echo "a - b : `expr ${a} - ${b}`"
echo "a * b : `expr ${a} \* ${b}`"
echo "a / b : `expr ${a} / ${b}`"
echo "a % b : `expr ${a} % ${b}`"
# 这里暂时用^符号来表示指数
echo "a^b : $((${a}**${b}))"

执行结果:
1

二、赋值运算符

运算符说明示例
=赋值c=3 a=${c}则a为3
+=加赋值如果a为3,b为2,则((a+=b))后a为5,b为2
-=减赋值如果a为3,b为2,则((a-=b))后a为1,b为2
*=乘赋值如果a为3,b为2,则((a*=b))后a为6,b为2
/=除赋值如果a为3,b为2,则((a/=b))后a为1,b为2
%=取模赋值如果a为3,b为2,则((a%=b))后a为1,b为2
<<=左移位赋值如果a为3,b为2,则((a<<=b))后a为12,b为2
>>=右移位赋值如果a为3,b为2,则((a>>=b))后a为0,b为2
&=按位与赋值如果a为3,b为2,则((a&=b))后a为2,b为2
|=按位或赋值如果a为3,b为2,则((a|=b))后a为3,b为2
^=按位异或赋值如果a为3,b为2,则((a^=b))后a为1,b为2

可以使用(( ))let命令进行运算,let(( ))用法类似,都是用于整数运算。

示例如下:

#!/bin/bash

a=3
b=2
echo "a:${a},b:${b}"
((a+=b))
echo "a+=b : a:${a},b:${b}"
a=3
b=2
((a-=b))
echo "a-=b : a:${a},b:${b}"
a=3
b=2
((a*=b))
echo "a*=b : a:${a},b:${b}"
a=3
b=2
((a/=b))
echo "a/=b : a:${a},b:${b}"
a=3
b=2
((a%=b))
echo "a%=b : a:${a},b:${b}"
a=3
b=2
((a<<=b))
echo "a<<=b : a:${a},b:${b}"
a=3
b=2
((a>>=b))
echo "a>>=b : a:${a},b:${b}"
a=3
b=2
((a&=b))
echo "a&=b : a:${a},b:${b}"
a=3
b=2
((a|=b))
echo "a|=b : a:${a},b:${b}"
a=3
b=2
((a^=b))
echo "a^=b : a:${a},b:${b}"

执行结果:
2

三、关系运算符

test[][[ ]]中使用的关系运算符:

运算符说明示例
-eq(equal)检测两个数是否相等,是返回0,否则返回1。如果a为3,b为2,则[ ${a} -eq ${b} ]返回1
-ne(not equal)检测两个数是否不相等,是返回0,否则返回1。如果a为3,b为2,则[ ${a} -ne ${b} ]返回0
-gt(greater than)检测左边的数是否大于右边的,是返回0,否则返回1。如果a为3,b为2,则[ ${a} -gt ${b} ]返回0
-lt(less than)检测左边的数是否小于右边的,是返回0,否则返回1。如果a为3,b为2,则[ ${a} -lt ${b} ]返回1
-ge(greater equal)检测左边的数是否大于等于右边的,是返回0,否则返回1。如果a为3,b为2,则[ ${a} -ge ${b} ]返回0
-le(less equal)检测左边的数是否小于等于右边的,是返回0,否则返回1。如果a为3,b为2,则[ ${a} -le ${b} ]返回1

每一条Shell命令,在退出(运行结束)时都会返回一个比较小的整数值给调用它的程序,这就是命令的退出状态。一般来说,退出状态为0表示成功(true),非0表示失败(false),if语句的判定条件,从本质上判断的就是命令的退出状态。
[][[ ]]与里面的条件表达式之间要有空格,例如[${a}==${b}]是错误的,必须写成[ ${a} == ${b} ][]test是等价的。

示例如下:

#!/bin/bash

a=3
b=2
echo "a:${a},b:${b}"
if [ ${a} -eq ${b} ]
then
    echo "${a} -eq ${b} : a等于b"
else
    echo "${a} -eq ${b} : a不等于b"
fi
if [ ${a} -ne ${b} ]
then
    echo "${a} -ne ${b} : a不等于b"
else
    echo "${a} -ne ${b} : a等于b"
fi
if [ ${a} -gt ${b} ]
then
    echo "${a} -gt ${b} : a大于b"
else
    echo "${a} -gt ${b} : a不大于b"
fi
if [ ${a} -lt ${b} ]
then
    echo "${a} -lt ${b} : a小于b"
else
    echo "${a} -lt ${b} : a不小于b"
fi
if [ ${a} -ge ${b} ]
then
    echo "${a} -ge ${b} : a大于或等于b"
else
    echo "${a} -ge ${b} : a小于b"
fi
if [ ${a} -le ${b} ]
then
    echo "${a} -le ${b} : a小于或等于b"
else
    echo "${a} -le ${b} : a大于b"
fi

执行结果:
3
(())中使用的关系运算符:

运算符示例
==检测两个数是否相等,是返回0,否则返回1。如果a为3,b为2,则((a==b))返回1
!=检测两个数是否不相等,是返回0,否则返回1。如果a为3,b为2,则((a!=b))返回0
>检测左边的数是否大于右边的,是返回0,否则返回1。如果a为3,b为2,则((a>b))返回0
>=检测左边的数是否大于等于右边的,是返回0,否则返回1。如果a为3,b为2,则((a>=b))返回0
<检测左边的数是否小于右边的,是返回0,否则返回1。如果a为3,b为2,则((a<b))返回1
<=检测左边的数是否小于等于右边的,是返回0,否则返回1。如果a为3,b为2,则((a<=b))返回1

关系运算符只支持整数数字,不支持字符串,除非字符串的值是整数数字。注意(( ))中表达式的值不是0,返回状态才是0,否则返回状态是1,(( ))进行整数比较的时候表达式的值与(())返回状态正好相反,表达式的值为0,返回状态为1,表达式的值为1,返回状态为0。

(( ))中使用的示例如下:

#!/bin/bash

a=3
b=2
echo "a:${a},b:${b}"
if ((a==b))
then 
    echo "${a}==${b} : a等于b"
else
    echo "${a}==${b} : a不等于b"
fi
if ((a!=b))
then 
    echo "${a}!=${b} : a不等于b"
else
    echo "${a}!=${b} : a等于b"
fi
if ((a>b))
then 
    echo "${a}>${b} : a大于b"
else
    echo "${a}>${b} : a不大于b"
fi
if ((a>=b))
then 
    echo "${a}>=${b} : a大于或等于b"
else
    echo "${a}>=${b} : a小于b"
fi
if ((a<b))
then 
    echo "${a}<${b} : a小于b"
else
    echo "${a}<${b} : a不小于b"
fi
if ((a<=b))
then 
    echo "${a}<=${b} : a小于或等于b"
else
    echo "${a}<=${b} : a大于b"
fi

执行结果:
4

四、字符串运算符

可以在test[][[ ]]中使用:

运算符说明示例
==、=如果两个字符串相等,则为true。如果a为"expression",b为"expansion",则[[ ${a} == ${b} ]]返回1
!=如果两个字符串不相等,则为true。如果a为"expression",b为"expansion",则[[ ${a} != ${b} ]]返回0
>如果左边字符串在字典顺序上排在右边字符串之后,则为true。如果a为"expression",b为"expansion",则[[ ${a} > ${b} ]]返回0
<如果左边字符串在字典顺序上排在右边字符串之前,则为true。如果a为"expression",b为"expansion",则[[ ${a} < ${b} ]]返回1
-z如果字符串的长度为零,则为true。如果a为"expression",则[[ -z ${a} ]]返回1
-n、string如果字符串的长度不为零,则为true。如果a为"expression",则[[ -n ${a} ]][[ ${a} ]]返回0

注意:

  • test[][[ ]]中使用字符串运算符===!=><只能比较字符串(只是字符串的值为数字时可以把它当成数字来比较,这只是字符串比较的结果与数值比较正好巧合,不推荐用它来比较数字,如[[ -3 < -2 ]]返回1,[[ 03 < 2 ]]返回0,[[ 1.5 == 1.50 ]]返回1,都是错误结果。
  • 如果要使用test[][[ ]]比较整数,需使用关系运算符-eq-ne-gt-lt-ge-le,推荐在(( ))中使用关系运算符==!=><>=<=进行整数比较。
  • test[]使用><需要加\转义,[[ ]]则不需要转义。
  • 使用test[][[ ]]则没有>=<=,可以通过[ ${a} \> ${b} -o ${a} == ${b} ][[ ${a} > ${b} || ${a} == ${b} ]]这种方式替代。
  • test[]会进行单词拆分,而[[ ]]不会进行单词拆分。
  • 当与[[ ]]一起使用时,<>使用当前区域设置按字典顺序排序,test命令使用ASCII排序。

示例如下:

#!/bin/bash

a="expression"
b="expansion"
echo "a:${a},b:${b}"
if [[ ${a} == ${b} ]]
then
    echo "${a} == ${b} : a等于b"
else
    echo "${a} == ${b} : a不等于b"
fi
if [[ ${a} = ${b} ]]
then
    echo "${a} = ${b} : a等于b"
else
    echo "${a} = ${b} : a不等于b"
fi
if [[ ${a} != ${b} ]]
then
    echo "${a} != ${b} : a不等于b"
else
    echo "${a} != ${b} : a等于b"
fi
if [[ ${a} > ${b} ]]
then 
    echo "${a} > ${b} : a大于b"
else
    echo "${a} > ${b} : a不大于b"
fi
if [[ ${a} > ${b} || ${a} == ${b} ]]
then 
    echo "${a} > ${b} || ${a} == ${b} : a大于或等于b"
else
    echo "${a} > ${b} || ${a} == ${b} : a小于b"
fi
if [[ ${a} < ${b} ]]
then 
    echo "${a} < ${b} : a小于b"
else
    echo "${a} < ${b} : a不小于b"
fi
if [[ ${a} < ${b} || ${a} == ${b} ]]
then 
    echo "${a} < ${b} || ${a} == ${b} : a小于或等于b"
else
    echo "${a} < ${b} || ${a} == ${b} : a大于b"
fi
if [[ -z ${a} ]]
then
    echo "-z ${a} : a长度为0"
else
    echo "-z ${a} : a长度不为0"
fi
if [[ -n ${a} ]]
then
    echo "-n ${a} : a长度不为0"
else
    echo "-n ${a} : a长度为0"
fi
if [[ ${a} ]]
then
    echo "${a} : a长度不为0"
else
    echo "${a} : a长度为0"
fi

执行结果:
5

五、布尔运算符

运算符说明示例
-a与运算,两个表达式都为true才返回true。如果a为3,b为2,则[ ${a} -gt 1 -a ${b} -lt 1 ]返回false
-o或运算,有一个表达式为true,则返回true。如果a为3,b为2,则[ ${a} -gt 1 -o ${b} -lt 1 ]返回true
!非运算,表达式为true,则返回false,否则返回true。如果b为2,则[ ! ${b} -lt 1 ]返回true

-a-o)必须在[]中或配合test命令使用。

示例如下:

#!/bin/bash

a=3
b=2
echo "a:${a},b:${b}"
if [ ${a} -gt 1 -a ${b} -lt 1 ]
then
    echo "${a} -gt 1 -a ${b} -lt 1 : return true"
else
    echo "${a} -gt 1 -a ${b} -lt 1 : return false"
fi
if [ ${a} -gt 1 -o ${b} -lt 1 ]
then
    echo "${a} -gt 1 -o ${b} -lt 1 : return true"
else
    echo "${a} -gt 1 -o ${b} -lt 1 : return false"
fi
if [ ! ${b} -lt 1 ]
then
    echo "! ${b} -lt 1 : return true"
else
    echo "! ${b} -lt 1 : return false"
fi

执行结果:
6

六、逻辑运算符

运算符说明示例
&&逻辑与如果a为3,b为2,则[[ ${a} > 1 && ${b} < 1 ]]返回false
||逻辑或如果a为3,b为2,则[[ ${a} > 1 || ${b} < 1 ]]返回true
!逻辑非如果b为2,则[[ ! ${b} < 1 ]]返回true

&&||可以在[[ ]](( ))中使用,不能在test[]中使用,!可以在[[ ]]中使用,不能在(( ))中使用。

示例如下:

#!/bin/bash

a=3
b=2
echo "a:${a},b:${b}"
if [[ ${a} > 1 && ${b} < 1 ]]
then
    echo "${a} > 1 && ${b} < 1 : return true"
else
    echo "${a} > 1 && ${b} < 1 : return false"
fi
if [[ ${a} > 1 || ${b} < 1 ]]
then
    echo "${a} > 1 || ${b} < 1 : return true"
else
    echo "${a} > 1 || ${b} < 1 : return false"
fi
if [[ ! ${b} < 1 ]]
then
    echo "! ${b} < 1 : return true"
else
    echo "! ${b} < 1 : return false"
fi

执行结果:
7

七、位运算符

运算符说明示例
<<左移位((3<<2))结果为12
>>右移位((6>>2))结果为1
&按位与((6&3))结果为2
|按位或((6|3))结果为7
^按位异或((6^3))结果为5
~按位非((~6))结果为-7

示例如下:

#!/bin/bash

echo "3<<2 : $((3<<2))"
echo "6>>2 : $((6>>2))"
echo "6&3 : $((6&3))"
echo "6|3 : $((6|3))"
echo "6^3 : $((6^3))"
echo "~6 : $((~6))"

执行结果:
8

八、文件测试运算符

运算符说明示例
-a file如果文件存在,则为true。[ -a ${file} ]
-b file如果文件存在并且是个块设备文件,则为true。[ -b ${file} ]
-c file如果文件存在并且是个字符设备文件,则为true。[ -c ${file} ]
-d file如果文件存在并且是个目录,则为true。[ -d ${file} ]
-e file如果文件存在,则为true。[ -e ${file} ]
-f file如果文件存在并且是个普通文件(既不是目录也不是设备文件),则为true。[ -f ${file} ]
-g file如果文件存在并且设置了set-group-id位,则为true。[ -g ${file} ]
-h file、-L file如果文件存在并且是个符号链接,则为true。[ -h ${file} ]
-k file如果文件存在并且设置了“sticky”位,则为true。[ -k ${file} ]
-p file如果文件存在并且是个命名管道(FIFO),则为true。[ -p ${file} ]
-r file如果文件存在并且可读,则为true。[ -r ${file} ]
-s file如果文件存在并且大小大于0,则为true。[ -s ${file} ]
-u file如果文件存在并且设置了set-user-id位,则为true。[ -u ${file} ]
-w file如果文件存在并且可写,则为true。[ -w ${file} ]
-x file如果文件存在并且可执行,则为true。[ -x ${file} ]
-G file如果文件存在并且被有效组id所拥有,则为true。[ -G ${file} ]
-N file如果文件存在并且自上次读取后被修改,则为true。[ -N ${file} ]
-O file如果文件存在并且被有效用户id所拥有,则为true。[ -O ${file} ]
-S file如果文件存在并且是个套接字,则为true。[ -S ${file} ]
file1 -ef file2如果file1和file2指向相同的设备和inode号,则为true。[ ${file1} -ef ${file2} ]
file1 -nt file2如果file1比file2更新(根据修改日期),或者file1存在而file2不存在,则为true。[ ${file1} -nt ${file2} ]
file1 -ot file2如果file1比file2更旧,或者file2存在而file1不存在,则为true[ ${file1} -ot ${file2} ]

除非另有说明,以上操作文件的表达式将跟随符号链接去操作其指向的目标,而不是链接本身。

示例如下:
9

有两个用来测试的文件,如上图所示,下面代码中只测试其中一部分运算符。

#!/bin/bash

file1="/root/test1.sh"
file2="/root/test2.sh"

if [[ -a ${file1} ]]
then
    echo "-a ${file1} : file1存在"
else
    echo "-a ${file1} : file1不存在"
fi
if [[ -b ${file1} ]]
then
    echo "-b ${file1} : file1是块设备文件"
else
    echo "-b ${file1} : file1不是块设备文件"
fi
if [[ -c ${file1} ]]
then
    echo "-c ${file1} : file1是字符设备文件"
else
    echo "-c ${file1} : file1不是字符设备文件"
fi
if [[ -d ${file1} ]]
then
    echo "-d ${file1} : file1是目录"
else
    echo "-d ${file1} : file1不是目录"
fi
if [[ -e ${file1} ]]
then
    echo "-e ${file1} : file1存在"
else
    echo "-e ${file1} : file1不存在"
fi
if [[ -f ${file1} ]]
then
    echo "-f ${file1} : file1是普通文件"
else
    echo "-f ${file1} : file1不是普通文件"
fi
if [[ -h ${file1} ]]
then
    echo "-h ${file1} : file1是符号链接"
else
    echo "-h ${file1} : file1不是符号链接"
fi
if [[ -L ${file1} ]]
then
    echo "-L ${file1} : file1是符号链接"
else
    echo "-L ${file1} : file1不是符号链接"
fi
if [[ -r ${file1} ]]
then
    echo "-r ${file1} : file1可读"
else
    echo "-r ${file1} : file1不可读"
fi
if [[ -s ${file1} ]]
then
    echo "-s ${file1} : file1大小大于0"
else
    echo "-s ${file1} : file1大小为0"
fi
if [[ -w ${file1} ]]
then
    echo "-w ${file1} : file1可写"
else
    echo "-w ${file1} : file1不可写"
fi
if [[ -x ${file1} ]]
then
    echo "-x ${file1} : file1可执行"
else
    echo "-x ${file1} : file1不可执行"
fi
if [[ -G ${file1} ]]
then
    echo "-G ${file1} : file1被有效组id所拥有"
else
    echo "-G ${file1} : file1没有被有效组id所拥有"
fi
if [[ -O ${file1} ]]
then
    echo "-O ${file1} : file1被有效用户id所拥有"
else
    echo "-O ${file1} : file1没有被有效用户id所拥有"
fi
if [[ -S ${file1} ]]
then
    echo "-S ${file1} : file1是套接字"
else
    echo "-S ${file1} : file1不是套接字"
fi
if [ ${file1} -nt ${file2} ]
then
    echo "${file1} -nt ${file2} : file1比file2新"
else
    echo "${file1} -nt ${file2} : file1不比file2新"
fi
if [ ${file1} -ot ${file2} ]
then
    echo "${file1} -ot ${file2} : file1比file2旧"
else
    echo "${file1} -ot ${file2} : file1不比file2旧"
fi

执行结果:
10

九、运算符优先级

以下运算符按优先级分组,优先级由下表所示,数字越低,优先级越高:

优先级运算符说明
1id++、id–后增、后减
2++id、–id先增、先减
3-、+单目负号、单目正号
4!、~逻辑非、按位非
5**幂运算
6*、/、%乘、除、取模
7+、-加、减
8<<、>>左移位、右移位
9<=、>=、<、>比较
10==、!=相等、不等
11&按位与
12^按位异或
13|按位或
14&&逻辑与
15||逻辑或
16expr ? expr : expr条件运算符
17=、+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^=赋值
18expr, expr逗号运算
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RtxTitanV

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值