今天我们继续学习shell编程语言的内容

发布于:2025-09-03 ⋅ 阅读:(21) ⋅ 点赞:(0)

四、Shell脚本语言的运算


4.1 算数运算

shell支持算术运算,但只支持整数,不支持小数

4.2 Bash中的算术运算
-- + 加法运算
-- - 减法运算
-- * 乘法运算
-- / 除法运算
-- % 取模,即取余数
-- ** 乘方 
​
#乘法符号在有些场景需要转义
4.2 实现算术运算

1. let var=算术表达式
2. var=$[算术表达式]
3. var=$((算术表达式))
4. var=$(expr arg1 arg2 arg3 ...)
5. declare -i var = 数值
6. echo '算术表达式' | bc  (支持浮点数)

4.3 增强型赋值:
+= 
i+=10 <==> i=1+10
-=
i-=j  <==> i=i-j
*=
/=
%=
++ 
i++,++i <==> i=i+1 (自增)
--
i--,--i <==> i=i-1 (自减)

实例:

[root@localhost ~]#  let var+=1
[root@localhost ~]# echo $var
1
[root@localhost ~]# let var++
[root@localhost ~]# echo $var
2
[root@localhost ~]# let var-=1
[root@localhost ~]# echo $var
1
[root@localhost ~]# let var--
[root@localhost ~]# echo $var
0

# i++ 与 ++i的区别:
i++ 先赋值再运算
++i 先运算再赋值

[root@localhost ~]# unset i j ;i=1;let j=i++;echo "i=$i,j=$j"
i=2,j=1
[root@localhost ~]# unset i j ;i=1;let j=++i;echo "i=$i,j=$j"
i=2,j=2
[root@localhost ~]#

实例:鸡兔同笼问题

(1)

[root@localhost ~]# vim xiaojiji.sh
#!/bin/bash
HEAD=35
FOOT=94

RABBIT=$(((FOOT-HEAD-HEAD)/2))
CHICKEN=$[35-RABBIT]
echo "兔子的数量为:"$RABBIT
echo "鸡的数量为:"$CHICKEN
[root@localhost ~]# chmod +x xiaojiji.sh
[root@localhost ~]# ./xiaojiji.sh
兔子的数量为:12
鸡的数量为:23

(2)在脚本中写入变量,让用户在命令行写入需要计算的数值

[root@localhost ~]# vim xiaojiji.sh
#!/bin/bash
HEAD=$1
FOOT=$2

RABBIT=$(((FOOT-HEAD-HEAD)/2))
CHICKEN=$[35-RABBIT]
echo "兔子的数量为:"$RABBIT
echo "鸡的数量为:"$CHICKEN
[root@localhost ~]# ./xiaojiji.sh 30 80
兔子的数量为:10
鸡的数量为:25

4.2 逻辑运算(了解,不用掌握)

True用数字表示1,False用数字表示0

  • 与:&

    1 与 1 = 1   
    1 与 0 = 0
    0 与 1 = 0
    0 与 0 = 0
  • 或:|

    1 或 1 = 1
    1 或 0 = 1
    0 或 1 = 1
    0 或 0 = 0
  • 非:!

    !1 = 0  !True=False
    !0 = 1  !False=True
  • 异或:^

    #异或的两个值,相同为假,不同为真
    1 ^ 1 =0
    1 ^ 0 =1
    0 ^ 1 =1
    0 ^ 0 =0

条件表达式


条件测试命令

条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成测试过程,实现评估布尔声明,以便在条件性环境下进行执行。

  • 若真,则状态码变量$?返回0

  • 若假,则状态码变量$?返回1

扩展: [ ] 与 [[ ]] 的区别

区别1:
[ ]是符合POSIX标准的测试语句,兼容性强,几乎可以运行在所有的Shell解释器中
[[ ]]仅可运行在特定的几个Shell解释器中(如Bash)

区别2:

[[ ]] 里面支持数学类型的操作数。例如:< >。但不支持 =号。
 

[root@localhost ~]# [[ 2 >= 1 ]]
-bash: 条件表达式中有语法错误
[root@localhost ~]# [[ 2 = 1 ]]
-bash: 未预期的记号 "2" 附近有语法错误
[root@localhost ~]# [[ 2 > 1 ]]
[root@localhost ~]# echo $?
0

[]是不能用这样的符号的例如 < >。

[root@localhost ~]# [ 1 > 2 ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ 2 > 1 ]
[root@localhost ~]# echo $?
0

((<))在两个括号中间可以不用对内容进行空格,并且可以执行<和>号

[root@localhost ~]# ((2>1))
[root@localhost ~]# echo $?
0
[root@localhost ~]#

=~ (等效于包含什么什么)

[root@localhost ~]# [[ "hello" =~ "p" ]]
[root@localhost ~]# echo $?
1
[root@localhost ~]# [[ "hello" =~ "h" ]]
[root@localhost ~]# echo $?
0

区别3:

在[ ]中使用 -a 表示逻辑与(两个都得满足) 和 -o 表示逻辑或 (满足其中一个就行)。

[[ ]]使用 && 逻辑与((前一个执行成功 后一个才执行),|| 表示 逻辑或(前一个执行失败 后一个才执行)。

[[ ]]不支持-a

区别4:

在[ ]中==是字符匹配(精确的)

[[ ]]中==是模式匹配(模糊的,可能是某一些)

区别5:

[ ]不支持正则匹配,

[[ ]]支持用=~(等效于包含什么什么)进行正则匹配

区别6:

[ ]仅在部分Shell中支持用()

进行分组,[[ ]]均支持

区别7:

在[ ]中如果变量没有定义,那么需要用双引号引起来(表示字符串)

在[[ ]]中不需要

字符串(sting),简写的时候写str

定义:1.啥也不写,2.单引号,3.双引号。

[root@localhost ~]# str1=hello
[root@localhost ~]# echo $str1
hello
[root@localhost ~]# str2='hello'
[root@localhost ~]# echo $str2
hello
[root@localhost ~]# str3="hello"
[root@localhost ~]# echo $str3
hello
[root@localhost ~]# 

‘ ‘ 引用不了变量值

“”或者啥也不因引用,会调出来原有字符串的含义

#当没有引起来的时候,$是被认识的
[root@localhost ~]# echo $str1$str2
hellohello
[root@localhost ~]# echo $str1 $str2
hello hello
[root@localhost ~]# echo $str1        $str2
hello hello

#用引号是代表一个整体
[root@localhost ~]# echo "$str1 $str2"
hello hello
#用!号在里面没有任何含义
[root@localhost ~]# echo "$str1 $str2!"
hello hello!
#但是在外面!是有含义的,代表调取上一个ls的命令。
[root@localhost ~]# !ls

获取字符串的长度

[root@localhost ~]# str1=hello 
[root@localhost ~]# echo ${#str1}
5
[root@localhost ~]#

截取字符信息(:0是从左到右进行,:0-1则为从右到左进行)

[root@localhost ~]# str1=hello 
#截取hllo,(:0代表的从左到右第一个字符, :1代表的是从左到右输出1个字符)
[root@localhost ~]# echo ${str1:0:1}
h
#截取hllo,(:0代表的从左到右第一个字符, :1代表的是从左到右输出2个字符)
[root@localhost ~]# echo ${str1:0:2}
he
#截取hllo,(:1代表的从左到右第2个字符, :1代表的是从左到右输出1个字符)
[root@localhost ~]# echo ${str1:1:1}
e
#截取hllo,(:1代表的从左到右第2个字符, :1代表的是从左到右输出2个字符)
[root@localhost ~]# echo ${str1:1:2}
el
#截取hllo,(:1代表的从右到左第1个字符, :1代表的是从左到右输出2个字符)
[root@localhost ~]# echo ${str1:0-1:2}
o
#同理
[root@localhost ~]# echo ${str1:0-1:1}
o
[root@localhost ~]# echo ${str1:0-2:1}
l
[root@localhost ~]# echo ${str1:0-2:2}
lo

对字符串内容进行正输出和反输出

#横向反输出hello
[root@localhost ~]# str1=hello 
[root@localhost ~]# echo ${str1:0-1:1}${str1:0-2:1}${str1:0-3:1}${str1:0-4:1}${str1:0-5:1}  
olleh
[root@localhost ~]# 

#竖向反输出(ken代表的是字符串的长度)
[root@localhost ~]# str1=hello 
[root@localhost ~]# len=${#str1}
[root@localhost ~]# echo $len
5
[root@localhost ~]# for i in `seq 1 $len`;do echo ${str1:0-$i:1};done
o
l
l
e
h
[root@localhost ~]# 


#利用for语句进行反输出(vim编辑中的最后一个echo是为了让输出内容进行换行)
[root@localhost ~]# vim m123.sh
#!/bin/bash
str1=$1
len=${#str1}
for i in `seq 1 $len`
do
        echo -n ${str1:0-$i:1}
done
echo
[root@localhost ~]# chmod +x m123.sh
[root@localhost ~]# ./m123.sh 123
321

从指定字符串开始截取(意思就是用#号截右边的所有内容,要么就是用%号截取左边的所有内容)

# 对内容从左向右第1个l开始截,保留右边的内容。(用#号)

[root@localhost ~]# str1=hello
[root@localhost ~]# echo ${str1#*l}
lo

# 对内容从左向右第2个l开始截,保留右边的内容。(用#号)

[root@localhost ~]# echo ${str1##*l}
o

# 对内容从右向左第1个l开始截,保留左边的内容。(用%号)

[root@localhost ~]# echo ${str1%l*}
hel

# 对内容从右向左第2个l开始截,保留左边的内容。(用%号)

[root@localhost ~]# echo ${str1%%l*}
he

#也可以多个字符截取

[root@localhost ~]# echo ${str1#*el}
lo

#实战效果

[root@localhost ~]# str1=/dev/sdb
[root@localhost ~]# echo ${str1##*/}
sdb
[root@localhost ~]# str1=/etc/yum.repos.d
[root@localhost ~]# echo ${str1##*/}
yum.repos.d
[root@localhost ~]# 

printf格式化输出(利用该命令进行设定内容)


常用格式替换符

替换符 功能
%s 字符串
%f 浮点格式,保留小数点位数%.nf,n为数字
%b 相对应的参数中包括转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义
%c ASCII字符,即显示对应参数的第一个字符
%d,%i 十进制整数
%o 八进制值
%u 不带正负号的十进制值
%x 十六进制值(a-f)
%X 十六进制值(A-F)
%% 表示%本身

常用转义字符

\n 换行
\r 回车
\t 水平制表符

#可以进行换行

[root@localhost ~]# printf "a\n"
a

#百分数就是(%d%)但为10进制数,s%就是字符串(自行设定内容)

[root@localhost ~]# printf "我名字是%s.今年%d岁! \n " lynn 23
我名字是lynn.今年23岁! 
 [root@localhost ~]# printf "我名字是%s.今年%d岁! \n " lynn 23.5
-bash: printf: 23.5: 无效的数字
我名字是lynn.今年23岁! 
 [root@localhost ~]# 

#保留几位小数就是(%.几f),s%就是字符串(自行设定内容)

[root@localhost ~]# printf "我名字是%s.今年%.2f岁! \n " lynn 23.5
我名字是lynn.今年23.50岁! 
 [root@localhost ~]# printf "我名字是%s.今年%.2f岁! \n " lynn 23.54
我名字是lynn.今年23.54岁! 
 [root@localhost ~]# printf "我名字是%s.今年%.3f岁! \n " lynn 23.546
我名字是lynn.今年23.546岁! 
 [root@localhost ~]#

#对中间内容进行空格,(正的就是内容左边空几个,负的就是内容右边空几个)

[root@localhost ~]# printf "我名字是%10s.今年%d岁! \n " lynn 23
我名字是      lynn.今年23岁! 
 [root@localhost ~]# printf "我名字是%-10s.今年%d岁! \n " lynn 23
我名字是lynn      .今年23岁! 
 [root@localhost ~]#

变量测试


1.变量测试
-v(看变量是否被定义)

#检测出str5没有被定义内容

[root@localhost ~]# [ -v str5 ]
[root@localhost ~]# echo $?
1
-R(看变量是否被引用

#可以看到是str5设置的变量,没有被用过

[root@localhost ~]# str5=666
[root@localhost ~]# [ -R str5 ]
[root@localhost ~]# echo $?
127
2.文件测试表达式

拓展:以前的知识:bash 后面跟文件名,可以直接执行该文件。

下面表格的选项可以按照案例格式,对文件进行检测

常用的文件测试操作符 说明
-a/-e 文件 文件是否存在
-d 文件 文件存在且为目录则为真,即测试表达式成立
-f 文件 文件存在且为普通文件则为真,即测试表达式成立
-r 文件 文件存在且可读为真
-w 文件 文件存在且可写为真
-x 文件 文件存在且可执行则为真

#检测/boot,/boot1,/boot2是否存在 (利用-e)

[root@localhost ~]# [ -e /boot ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ -e /boot1 ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# [ -e /boot2 ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# 
3.字符串测试

拓展:unset str1(删除字符串1及其信息)

常用字符串测试操作符 说明
-n ”字符串“ 若字符串的长度不为0,则为真,即测试表达式成立,n可以理解为nozero
-z ”字符串“ 若字符串的长度为0,则为真,z可以理解为zero
> Ascii码是否大于Ascii码
“字符串1” == ”字符串2“ 若字符串1内容等于字符串2内容,则为真
“字符串1” != ”字符串2“ 若字符串1内容不等于字符串2内容,则为真
“字符串1” =~ “字符串2” 左侧字符串是否能被右侧的PATTERN所匹配。注意:此表达式用于[[ ]]中:扩展的正则表达式

#测试字符串123,根据上面的选项,输出为0为符合相应选项要求,非0则不符合。

[root@localhost ~]# str1=123
[root@localhost ~]# [ -n $str1 ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ -z $str1 ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# 

#利用=~时的操作,注意和上面的案例还是有区别的,中括号多了

[root@localhost ~]# str1=123
[root@localhost ~]# [[ $str1 =~ $str2 ]]
[root@localhost ~]# echo $?
1
[root@localhost ~]# str2=123
[root@localhost ~]# [[ $str1 =~ $str2 ]]
[root@localhost ~]# echo $?
0

拓展:

#利用脚本进行设置信息(通过脚本进行简单的设置)

[root@localhost ~]# vim test.sh
#!/bin/bash
[ -z $1 ] && echo "请输入参数!" || echo ok 
[root@localhost ~]# chmod +x test.sh
[root@localhost ~]# ./test.sh
请输入参数!
[root@localhost ~]# ./test.sh 1
ok
4.整数测试
在[ ] 或 test中使用的比较符号 在(()) 或 [[ ]]中使用的比较符号(不用这个做数字比较) 说明
-eq \== 或 = 相等,equal
-ne != 不相等,not equal
-gt > 大于,greater than
-ge > = 大于等于,greater equal
-lt < 小于,less than
-le < = 小于等于,less equal

#利用上面的选项,进行利用功能,下面举例来证明上面选项怎么用

[root@localhost ~]# [ 1 -eq 1 ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ 1 -ne 1 ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# 

逻辑操作符


在[ ] 中使用的操作符 在test, [[ ]] , (( ))中使用的逻辑操作符 说明
-a && and,与,两边都为真,则结果为真
-o || or,或,有真则真,同假则假
not,非,两端相反,则结果相反

#举例说明,根据上面选项,符合要求输出为0,不符合就为非0。举例看格式

[root@localhost ~]# [ 1 -eq 3 -o 1 -gt 0 ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ 1 -eq 3 -a 1 -gt 0 ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# 

拓展:

#利用&&和|| 操作,需添加中括号

[root@localhost ~]# [[ 1 -eq 3 && 1 -gt 0 ]]
[root@localhost ~]# echo $?
1
[root@localhost ~]# [[ 1 -eq 3 || 1 -gt 0 ]]
[root@localhost ~]# echo $?
0
[root@localhost ~]#

关于()与 { }


案例

#括号内的内容为子内容,子内容不用影响夫内容。

[root@localhost ~]# name=lisi;(echo $name;name=zhangsan;echo $name);echo $name
lisi
zhangsan
lisi
[root@localhost ~]# 

#{}这个括号,会影响到父内容。

[root@localhost ~]# name=lisi; { echo $name;name=zhangsan;echo $name; } ;echo $name
lisi
zhangsan
zhangsan
[root@localhost ~]# 

实验演示1


#磁盘空间的判断(看磁盘是不是充足),若超出80则提示空间不足。(没使用脚本)

[root@localhost ~]# df -Th
文件系统                   类型      大小  已用  可用 已用% 挂载点
/dev/mapper/openeuler-root ext4       69G  2.8G   63G    5% /
devtmpfs                   devtmpfs  4.0M     0  4.0M    0% /dev
tmpfs                      tmpfs     1.7G     0  1.7G    0% /dev/shm
tmpfs                      tmpfs     4.0M     0  4.0M    0% /sys/fs/cgroup
efivarfs                   efivarfs  256K   51K  201K   21% /sys/firmware/efi/efivars
tmpfs                      tmpfs     675M   13M  662M    2% /run
tmpfs                      tmpfs     1.7G     0  1.7G    0% /tmp
/dev/sda2                  ext4      974M  197M  710M   22% /boot
/dev/sda1                  vfat      599M  6.1M  593M    2% /boot/efi
/dev/mapper/openeuler-home ext4      124G   40K  118G    1% /home
[root@localhost ~]# jkl_=$(df |head -2 |tail -1 |tr -s ' '|cut -d ' ' -f5 |cut -d"%" -f1)
[root@localhost ~]# echo $jkl_
5
[root@localhost ~]# [ $jkl_ -gt 80 ] && echo "磁盘空间不足" || echo " 磁盘空间充足"
磁盘空间充足

实验演示2


使用read命令命令来接受输入

Option 说明
-a array 把读取的数据赋值给数组array,从下标0开始
-p prompt 显示提示信息,提示内容为prompt
-s 静默模式(Silent mode),不会再屏幕上显示输入的字符。例如:输入密码
-t seconds 设置超时时间,单位为秒。如果用户没能按时完成,返回一个非0的退出状态

#使用read,赋值多个数据进行输出,-p的选项为显示提示信息。注意看变量信息。-s为静默密码(在输入密码过程时没有显示)。

[root@localhost ~]# vim test.sh
#!/bin/bash
read -p "请输入你的姓名: " name
echo "Hello,$name !"
read -p "请输入你的年龄: " age
[ $age -lt 30 ] && echo "Oh,行!" || echo "Oh,deadman,deadman!"
read -s -p "请输入密码" password
echo $password
[root@localhost ~]# chmod +x test.sh
[root@localhost ~]# ./test.sh
请输入你的姓名: lynn
Hello,lynn !
请输入你的年龄: 26
Oh,行!
请输入密码123
[root@localhost ~]# ./test.sh
请输入你的姓名: lynn
Hello,lynn !
请输入你的年龄: 66
Oh,deadman,deadman!
请输入密码123
[root@localhost ~]# 

流程控制


就是控制下当前的语句是否进行执行,或者是控制当前的语句在特定的条件下再执行。(可以让多个不同的指令相互关联起来了。)

if条件语句

1.单分支if

[root@localhost ~]# vim if.sh
#!/bin/bash
#单分支
read -p "请输入一个数字: " number1
if [ $number1 -gt 10 ]
then    
        echo "$number1 大于 10"
fi 
[root@localhost ~]# chmod +x if.sh
[root@localhost ~]# ./if.sh
请输入一个数字: 66
66 大于 10
[root@localhost ~]# 

2.双分支if

[root@localhost ~]# vim if.sh
#!/bin/bash
#双分支
read -p "请输入一个数字: " number1
if [ $number1 -gt 10 ]
then
        echo "$number1 大于 10"
else
        echo "$number1 不大于 10"
fi
[root@localhost ~]# ./if.sh
请输入一个数字: 8
8 不大于 10
[root@localhost ~]# 

3.多分支if(多条件)

[root@localhost ~]# vim if.sh
#!/bin/bash
#双分支
read -p "请你的成绩: " socore
if [ $socore -ge 90 -a $socore -le 100 ]
then
        echo "A"
elif [ $socore -ge 80 -a $socore -le 89 ]
then
        echo "B"
elif [ $socore -ge 60 -a $socore -le 79 ]
then
        echo "C"
elif [ $socore -ge 0 -a $socore -le 59 ]
then
        echo "D"
else
        echo "请输入0~100的成绩"
fi
[root@localhost ~]# ./if.sh
请你的成绩: 59
D
[root@localhost ~]# ./if.sh
请你的成绩: 101
请输入0~100的成绩
[root@localhost ~]# ./if.sh
请你的成绩: 66
C
[root@localhost ~]# ./if.sh
请你的成绩: 100
A
[root@localhost ~]# 

4.父子if语句

#父子if条件命令的演示(利用脚本,以sshd服务为例,如果关闭就尝试将其打开)

[root@localhost ~]# vim sshd_check_staus.sh
#!/bin/bash
process_stat=$(netstat -anpt | grep sshd | wc -l)
if [ $process_stat -gt 0 ];then
        echo "sshd is running"
        systemctl status sshd | grep "active"
else
        echo "sshd is running"
        systemctl start sshd
        sleep 2
        process_stat=$( netstat -anpt | grep sshd wc -l )
        if [ $process_stat -gt 0 ];then
                echo "sshd run successful"
        else
                echo "sshd no method to start,please check"
        fi
fi
[root@localhost ~]# chmod +x sshd_check_staus.sh
[root@localhost ~]# ./sshd_check_staus.sh 
sshd is running
     Active: active (running) since Tue 2025-09-02 16:52:26 CST; 8h ago
             └─163391 grep active


网站公告

今日签到

点亮在社区的每一天
去签到