linux操作系统---小白玩转shell脚本

目录

shell脚本

脚本检查工具

、Shell脚本的用途:

[、 Shell脚本基本结构:](#、 Shell脚本基本结构:)

[、 脚本注释规范](#、 脚本注释规范)

[、 变量定义和引用](#、 变量定义和引用)

位置与预定义变量

退出状态码变量

防止扩展

加引号来防止扩展

变量扩展

Shell字符串详解***

Shell字符串拼接**

Shell字符串截取**

Shell的格式化输出printf***

、语法格式:

、常用格式替换符:

、常用转义字符:

​编辑

Shell脚本语言的运算

[4.1 算数运算](#4.1 算数运算)

[4.2 Bash中的算术运算](#4.2 Bash中的算术运算)

[4.2 实现算术运算](#4.2 实现算术运算)

增强型赋值:

条件测试命令

条件测试命令及其语法***

变量测试***

文件测试表达式

字符串测试表达式***

整数测试表达式***

逻辑操作符

[关于()和 { } 的区别](#关于()和 { } 的区别)

[关于(( ))和\[ ]](#关于(( ))和[[ ]])

组合测试条件

[第一种方式 ](#第一种方式[ ])

[第二种方式\[ ]](#第二种方式[[ ]])

read命令命令来接受输入

流程控制

条件选择

选择执行if语句

条件判断case语句

循环

for循环

while循环

循环控制语句

Shell数组的概念

采用键值对的形式赋值

动态定义数组数量

hell数组的打印

Shell数组的赋值

Shell数组的拼接合并

Shell删除数组元素

获取数组某范围的元素

数组元素的替换

Shell函数的定义

Shell函数的调用

Shell函数详解

案例1:计算两个数的和(带用户输入)

案例2:判断数字是否为正数

案例3:统计文件行数(带参数)

案例4:批量重命名文件(实用场景)


shell脚本

脚本检查工具

yum install -y epel-release

yum install -y shellcheck

、Shell脚本的用途:

  • 自动化常用命令

  • 执行系统管理和故障排除

  • 创建简单的应用程序

  • 处理文本或文件

    、 Shell脚本基本结构:

    Shell脚本编程:是基于过程式,解释执行的语言

    编程语言的基本结构:

    • 各种系统命令的组合

    • 数据存储:变量,数组

    • 表达式:a+b

    • 控制语句:if、case、for、while

    shell脚本:包含一些命令或声明,并符合一定格式的文本文件

    格式要求:首行执行shebang机制

    复制代码
    #声明后续语句是通过那种语言写的
    #!/bin/bash
    #!/usr/bin/python
    #!/usr/bin/perl
    ​
    #变量$SHELL
    [root@localhost ~]# echo $SHELL
    /bin/bash
    ​

、 脚本注释规范

  • 第一行一般为调用使用的语言

  • 程序名,避免更改文件名为无法找到正确的文件

  • 版本号

  • 更改后的时间

  • 作者相关信息

  • 该程序的作用,及注意事项

  • 最后是各版本的更新简要说明

复制代码
[root@localhost ~]# vim script1.sh 
#!/bin/bash
#auth:Mr Luo
#use:列出系统中所有的普通文件
#Date: 2025-06-05
#vresion: 1.0
cd /home
find /home -type f
​

、 变量定义和引用

变量的生效范围(变量作用域)

  • 普通变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效

  • 环境变量:生效范围为当前shell进程及其子进程

  • 本地变量:生效范围为当前shell进程中某代码片段,通常指函数

普通变量:当前shell环境下才有效,一但切入bash新shell就没有了

复制代码
[root@localhost ~]# a=1
[root@localhost ~]# echo $a
1
[root@localhost ~]# bash
[root@localhost ~]# echo $a
​
[root@localhost ~]# exit
exit
[root@localhost ~]# echo $a
1

环境变量:无线切换到子shell环境,会一直存在

  • 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量。

  • 一旦子进程修改了从父进程继承的变量,将会传递新的值给孙子进程

  • 一般只在配置文件中使用,在脚本中较少使用

变量声明和赋值

复制代码
export name=VALUE
declare -x name =VALUE
​
#或者先赋值再声明~
​
value可以是以下多种类型
直接字符串:name='root'
变量引用:name="$USER"
命令应用:name=`command`  || name=$(command)
通配符:FILE=/etc/* /*表示etc目录下所有的文件名*/
复制代码
[root@localhost ~]# export a=1
[root@localhost ~]# echo $a
1
[root@localhost ~]# bash
[root@localhost ~]# echo $a
1
[root@localhost ~]# exit
exit
[root@localhost ~]# echo $a

​

变量赋值:注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存。(数字一定不能" ")

变量引用:单引号和双引号是有区别的

弱引用和强引用:

  • "$name":弱引用,其中的变量引用会被替换成为变量值

  • '$name':强引用,其中的变量引用不会被替换成变量值,而保持原字符串

  • `` 反单引号是输出内容的结果

案例:

复制代码
[root@localhost ~]# nl=1
[root@localhost ~]# star=luo
[root@localhost ~]# echo $star
luo
[root@localhost ~]# star='luo'
[root@localhost ~]# echo '$star'
$star
[root@localhost ~]# star="luo"
[root@localhost ~]# echo "$star"
luo
[root@localhost ~]# star2=‘$star'
> ^C
[root@localhost ~]# star2='$star'
[root@localhost ~]# echo $star2
$star
[root@localhost ~]# star2="$star"
[root@localhost ~]# echo $star2
luo
[root@localhost ~]# name='luo'
[root@localhost ~]# echo "my name is $name"
my name is luo
​
`ls`  #注意反单引号  ` `  是输出内容的结果
[root@localhost ~]# result1=`ls`
[root@localhost ~]# echo $result1
公共 模板 视频 图片 文档 下载 音乐 桌面 anaconda-ks.cfg script1.sh
​
set  #查看所有变量命令
unset #删除变量

​
​

案例: { }的使用

复制代码
[root@localhost ~]# star=luo
[root@localhost ~]# star1=$star2222
[root@localhost ~]# echo $star1
​
[root@localhost ~]# star1=${star}2222
[root@localhost ~]# echo $star1
luo2222

显示系统信息:信息收集类脚本

复制代码
[root@localhost ~]# vim os.sh
#!/bin/bash
RED="\E[1;31m"
GREEB="\E[1;32m"
END="\E[0m"
echo -e "\E[1;32m----------Host systeminfo----------$END"
echo -e "HOSTNAME: $RED `hostname`$END"
echo -e "IPADDR:   $RED `ifconfig ens160 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n1` $END"
echo -e "OSVERSION: $RED `cat /etc/redhat-release`$END"
echo -e "KERNEL:   $RED `uname -r`$END"
echo -e "CPU:       $RED `lscpu | grep "型号名称:" | tr -s ' ' ' '|cut -d ' ' -f 2-5` $END"
echo -e "MEMORY:   $RED `free -h | grep Mem | tr -s ' ' ' '|cut -d ' ' -f 4` $END"
echo -e "DISK:     $RED `lsblk | grep '^sda' | tr -s ' ' | cut -d ' ' -f 4` $END"
echo -e "\E[1;32m----------       END     ----------$END"
[root@localhost ~]# vim os.sh
[root@localhost ~]# chmod +x os.sh
[root@localhost ~]# 
[root@localhost ~]# bash os.sh
----------Host systeminfo----------
HOSTNAME:  localhost.localdomain
IPADDR:    192.168.235.132 
OSVERSION:  Rocky Linux release 9.4 (Blue Onyx)
KERNEL:    5.14.0-427.13.1.el9_4.x86_64
CPU:        Intel(R) Core(TM) i7-14650HX 
MEMORY:    778Mi 
DISK:      200G 
----------       END     ----------

位置与预定义变量

位置变量:在Bash Shell中内置的变量,在脚本代码中调用命令行传递给脚本的参数

复制代码
​
$1,$2,... 对应第一个,第二个等参数,shift[n]换位置,最多9个
#预定义变量
$0  命令本身,包括路径
$*  传递给脚本的所有参数,全部参数合成一个字符串
$@  传递给脚本的所有参数,每个参数为独立字符串
$#  传递给脚本的参数的个数
$?  上个命令的退出状态,或函数的返回值
$$  当前shell进程ID。对于Shell脚本,就是这些脚本所在的进程ID
​
注意:$@,$*只有被双引号括起来的时候才会有差异
当指令正确时
#echo $?  输出结果为0(正确)
当指令错误时
#echo $? 输出结果为1,可能为其它数,反正不为0(错误)
复制代码
##$1,$2,... 对应第一个,第二个等参数,shift[n]换位置,最多9个
[root@luo ~]# vim script1.sh 
#!/bin/bash
#auth:Mr Luo
#use:列出系统中所有的普通文件
#Date: 2025-06-05
#vresion: 1.0
find $1 -type f
find $2 -type f
​
[root@luo ~]# ./script1.sh /home
/home/nginx-1.28.0.tar.gz
/home/luo/.bash_logout
/home/luo/.bash_profile
/home/luo/.bashrc
[root@luo ~]# vim script1.sh 
[root@luo ~]# ./script1.sh /home/ /etc/
/home/nginx-1.28.0.tar.gz
/home/luo/.bash_logout
/home/luo/.bash_profile
/etc/fstab
/etc/crypttab
/etc/lvm/devices/system.devices
/etc/lvm/archive/rl_00000-1251449233.vg
​
[root@luo ~]# vim script1.sh 
[root@luo ~]# ./script1.sh 1 2 3 4 5 6 7 8 9 10 11
1 2 3 4 5 6 7 8 9 10 11
[root@luo ~]# ./script1.sh 1 2 3 4 5 6 7 8 9 123 111
1 2 3 4 5 6 7 8 9 123 111
[root@luo ~]# ./script1.sh 1 2 3 4 5 6 7 8 9 123 111 124124124 11241
1 2 3 4 5 6 7 8 9 123 111
​
##预定义变量
[root@luo ~]# vim ./script1.sh 
#!/bin/bash
#auth:Mr Luo
#use:列出系统中所有的普通文件
#Date: 2025-06-05
#vresion: 1.0
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 
echo $0
echo $*
echo $@
echo $#
echo $?
echo $$
[root@luo ~]# ./script1.sh a s d f g h j k l 
a s d f g h j k l   #命令本身,包括路径
./script1.sh        
a s d f g h j k l   #所有的参数合成一个字符串输出
a s d f g h j k l   #每个参数独立字符串,单独输出
9               #传递给脚本的参数个数是9个
0       #返回值0 (0是正确,1是错误)
78482       #显示脚本所在进程id
复制代码
复制代码
[root@luo ~]# vim ./script1.sh 
#!/bin/bash
#auth:Mr Luo
#use:列出系统中所有的普通文件
#Date: 2025-06-05
#vresion: 1.0
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 
echo $0
for i in "$*"
do
        echo $i
done
for i in "$@"
do
        echo $i
done
echo $#
echo $?
echo $$
[root@luo ~]# ./script1.sh a s d f g h j k l
a s d f g h j k l
./script1.sh
a s d f g h j k l
a
s
d
f
g
h
j
k
l
9
0
82101
​
#通过简易脚本能看到预定变量之间的差异

清空所有位置变量

复制代码
set --
[root@luo ~]# ./script1.sh asdasdasdasdas
​
./script1.sh
​
0
0
83440
​
​
退出状态码变量

进程执行后,将使用变量 ? 保存状态码的相关数字,不同的值反应成功与失败, ?保存状态码的相关数字,不同的值反应成功与失败, ?保存状态码的相关数字,不同的值反应成功与失败,的取值范围为0,255

复制代码
#$?的值为0 代表成功
#$?的值不为0 代表失败

用户可以在脚本中使用以下命令自定义退出状态码

复制代码
exit 

当在脚本exit 22 echo $? 输出结果是22,是成功的

所有注意脚本里有没有exit

  • 脚本中一旦遇到了exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

  • 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

复制代码
​
[root@luo ~]# vim ./script1.sh 
#!/bin/bash
#auth:Mr Luo
#use:列出系统中所有的普通文件
#Date: 2025-06-05
#vresion: 1.0
set --
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 
echo $0
for i in "$*"
do
        echo $i
done
for i in "$@"
do
        echo $i
done
echo $#
echo $?
echo $$
exit 22
[root@luo ~]# ./script1.sh 
​
./script1.sh
​
0
0
84514
[root@luo ~]# echo $?
22
[root@luo ~]# echo $?
0
​
​
防止扩展
复制代码
反斜线(\)会使随后的字符按原意解释

实例:

复制代码
[root@localhost ~]# echo Your cost: \$5.00
Your cost: $5.00
[root@localhost ~]#
加引号来防止扩展
复制代码
单引号(' ')防止所有扩展
双引号(" ")可防止扩展,但是以下清空例外:$(美元符号)
变量扩展
复制代码
``:反引号,命令替换
\:反斜线,禁止单个字符扩展
!:叹号,历史命令替换

Shell字符串详解***

字符串(String)就是一系列字符的组合。字符串是Shell编程中最常用的数据类型之一

字符串可以由单引号''包围,也可以由""包围,也可以不用引号,三种方式的区别

  1. 由单引号' '包围的字符串

    • 任何字符都会原样输出,在其中使用变量是无效的

    • 字符串中不能出现单引号,即使对单引号进行转义也不行

  2. 由双引号" "包围的字符串

    • 如果其中包含了某个变量,那么该变量就会被解析(得到该变量的值),而不是原样输出

    • 字符串中可以出现双引号,只要进行转义就行

  3. 不被引号包围的字符串

    • 不被引号包围的字符串中出现变量也会被解析,这一点和双引号""包围的字符串一样

    • 字符串中不能出现空格,否则空格后面的字符串会作为其他变量或者命令解析

通过代码演示一下三种形式的区别

复制代码
#!/bin/bash
n=74
str1=c.biancheng.net$n 
str2="shell \"Script\" $n"
str3='C语言中文网 $n'
echo $str1
echo $str2
echo $str3
​
​
# 运行结果
c.biancheng.net74
shell "Script" 74
C语言中文网 $n

str1 中包含了$n,它被解析为变量 n 的引用。$n后边有空格,紧随空格的是 str2;Shell 将 str2 解释为一个新的变量名,而不是作为字符串 str1 的一部分

str2 中包含了引号,但是被转义了(由反斜杠\开头的表示转义字符)。str2 中也包含了$n,它也被解析为变量 n 的引用

str3 中也包含了$n,但是仅仅是作为普通字符,并没有解析为变量 n 的引用

复制代码
#单引号不会调取它的变量值
#双引号会调取
[root@luo ~]# bash script1.sh 
juexing.1
juexing"wanmei"1
c juexing $a
b asda 1
[root@luo ~]# vim ./script1.sh 
#!/bin/bash
#auth:Mr Luo
#use:列出系统中所有的普通文件
#Date: 2025-06-05
#vresion: 1.0
a=1
star1=juexing.$a
star2="juexing\"wanmei\"$a"
star3='c juexing $a'
star4="b asda $a"
echo $star1
echo $star2
echo $star3
echo $star4

获取字符串长度

在Shell中获取字符串长度很简单,具体方法如下:

加放括弧加#号

复制代码
[root@luo ~]# a=12345678
[root@luo ~]# echo ${#a}
8

Shell字符串拼接**

在脚本语言中,字符串的拼接(也称为字符串连接或者字符串合并)往往都非常简单,例如:

  • PHP中使用.即可连接两个字符串

  • JavaScript中使用+即可将两个字符串合并为一个

然而,在Shell中你不需要使用任何运算符,将两个字符串并排放在一起就能实现拼接

复制代码
#注意方括弧{ }的使用
[root@luo ~]# ac1=111
[root@luo ~]# ac2=222
[root@luo ~]# echo $ac1$ac2   #成功输出
111222
[root@luo ~]# echo $ac1$ac2ac3
111
[root@luo ~]# echo {$ac1$ac2}ac3  #放括弧错误使用
{111222}ac3
[root@luo ~]# echo $ac1{$ac2}ac3  #方括弧错误使用
111{222}ac3
[root@luo ~]# echo $ac1${ac2}ac3 #方括弧正确使用
111222ac3
​

Shell字符串截取**

Shell截取字符串通常有两种方式,从指定位置开始截取和从指定字符(子字符串)开始截取

从指定位置开始截取

这种方式需要两个参数:除了指定起始位置,还需要截取长度,才能最终确定要截取的字符串

既然需要指定起始位置,那么就要涉及到计数方向的问题,到底是从字符串左边开始计数,还是从字符串右边开始计数?答案是:Shell同时支持两种计数方式

1.从字符串左边开始计数

如果想从字符串的左边开始计数,那么截取字符串的具体格式如下:

复制代码
${string:start:length}
​
`其中,Sting是要截取的字符串,start是起始位置(从左边开始,从0开始计数),length是要截取的长度(省略的话表示直到字符串的末尾)

Shell的格式化输出printf***

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

说明:%s中的数字代表此替换符中的输出字符宽度,不足补空格,默认是右对齐,%-10s表示10个字符宽,-表示左对齐

、常用转义字符:
转义符 功能
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\\ 表示\本身
cpp 复制代码
[root@luo ~]# vim shp.sh
[root@luo ~]# ./shp.sh
请输入你的姓名:luo
请输入你的年龄:10
请输入你的性别:女
请输入你的电话:123
请输入你的体重:30
luo 你好,你的年龄为10,性别 女,电话 123,体重 30.00[root@luo ~]# 
[root@luo ~]# vim shp.sh
#!/bin/bash
read -p "请输入你的姓名:" name
read -p "请输入你的年龄:" age
read -p "请输入你的性别:" sex
read -p "请输入你的电话:" phone
read -p "请输入你的体重:" weight
printf "%s 你好,你的年龄为%d,性别 %s,电话 %d,体重 %.2f" $name $age $sex $phone $weight

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  (支持浮点数)
​
[root@luo ~]# let rs=2*2   #乘法
[root@luo ~]# echo $rs
4
[root@luo ~]# let rs=6-2  #减法
[root@luo ~]# echo $rs
4
[root@luo ~]# let rs=6/2  #除法
[root@luo ~]# echo $rs
3
[root@luo ~]# let rs=111111/333  #取模
[root@luo ~]# echo $rs
333
[root@luo ~]# let rs=10*10  #乘法
[root@luo ~]# echo $rs
100
[root@luo ~]# rs=$[2+2]
[root@luo ~]# echo $rs
4
[root@luo ~]# rs=$((3+3))
[root@luo ~]# echo $rs
6
[root@luo ~]# rs=$(expr 1+2) #报错
[root@luo ~]# echo $rs
1+2
[root@luo ~]# rs=$(expr 1+2 ) #报错
[root@luo ~]# echo $rs
1+2
[root@luo ~]# rs=$(expr 1 + 2 )  #报错
[root@luo ~]# echo $rs
3
[root@luo ~]# rs=$(expr 1 + 2)
[root@luo ~]# echo $rs
3
[root@luo ~]# rs=$[4**3]   #乘方
[root@luo ~]# echo $rs
64
复制代码
实例:使用bc计算小数和declare -i计算
[root@localhost ~]# echo "scale=3;20/3"|bc
6.666 
#scale意思是保留小数点几位,scale=3是保留小数点3位,20/3是20除以3, |管道符,交给bc去处理
增强型赋值:
复制代码
​
+= 
i+=10 <==> i=1+10
-=
i-=j  <==> i=i-j
*=
/=
%=
++ 
i++,++i <==> i=i+1 (自增)
--
i--,--i <==> i=i-1  (自减)
复制代码
[root@luo ~]# unset i
[root@luo ~]# i=10
[root@luo ~]# let i--
[root@luo ~]# echo $i
9
[root@luo ~]# let i*=2
[root@luo ~]# echo $i
18
[root@luo ~]# let i/=2
[root@luo ~]# echo $i
9
[root@luo ~]# let i%=2
[root@luo ~]# echo $i
1
[root@luo ~]# star=abc
[root@luo ~]# star+=$star
[root@luo ~]# star1+=$star
[root@luo ~]# echo $star1
abcabc
[root@luo ~]# star1+=$star
[root@luo ~]# echo $star1
abcabcabcabc
[root@luo ~]# star1+=$star
[root@luo ~]# echo $star1
abcabcabcabcabcabc
复制代码
​
[root@luo ~]# i=1
[root@luo ~]# let i++
[root@luo ~]# let rs=i++
[root@luo ~]# echo $rs
2
[root@luo ~]# let rs=i++
[root@luo ~]# echo $rs
3
[root@luo ~]# echo $rs
3
[root@luo ~]# let rs=i++
[root@luo ~]# echo $rs
4
[root@luo ~]# let rs=i++
[root@luo ~]# echo $rs
5
[root@luo ~]# let rs=i++
[root@luo ~]# echo $rs
6
[root@luo ~]# i=1
[root@luo ~]# let i--
[root@luo ~]# let rs=i--
[root@luo ~]# echo $rs
0
[root@luo ~]# let i--
[root@luo ~]# echo $rs
0
[root@luo ~]# let i--
[root@luo ~]# let rs=i--
[root@luo ~]# echo $rs
-3
[root@luo ~]# let i--
[root@luo ~]# let rs=i--
[root@luo ~]# echo $rs
-5
[root@luo ~]# let rs=i--
[root@luo ~]# echo $rs
-6
[root@luo ~]# let rs=i--
[root@luo ~]# echo $rs
-7

条件测试命令

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

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

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

条件测试命令及其语法***

test 用于检查文件属性、字符串比较、数值比较等,并返回 退出状态码0 表示真,1 表示假)

语法1:test <测试表达式> 说明:test命令和<测试表达式>之间至少有一个空格

复制代码
# 在shell中,大于用 -gt 表示,小于用 -lt 表示,大于或等于用 -ge 表示,小于或等于用 -le表示 ,不相等用-ne 表示
[root@luo ~]# test 1 -gt 2
[root@luo ~]# echo $?
1
[root@luo ~]# test 1 -lt 2
[root@luo ~]# echo $?
0

​

语法2:\<测试表达式\> 说明:该方法和test命令的用法一样,\[\]的两边和内容之间至少有一个空格

复制代码
[root@luo ~]# [ 2 -gt 4 ]
[root@luo ~]# echo $?
1
[root@luo ~]# [ 2 -lt 4 ]
[root@luo ~]# echo $?
0

语法3:\[ \<测试表达式\> ] 说明:比test和\[\]更新的语法格式。\[]的边界和内容之间至少有一个空格。\[]中可以使用通配符等进行模式匹配

cpp 复制代码
[root@luo ~]# [[ 4 >9 ]]
[root@luo ~]# echo $?
1
[root@luo ~]# [[ 5 >1 ]]
[root@luo ~]# echo $?
0

语法4:((<测试表达式>)) 说明:一般用于if语句里,双小括号两端不需要有空格,测试对象只能是整数

cpp 复制代码
[root@luo ~]# ((3>4))
[root@luo ~]# echo $?
1
[root@luo ~]# ((6>4))
[root@luo ~]# echo $?
0
变量测试***

语法规则:-v VAR 变量var是否被定义

示例:判断NAME变量是否被定义

root@luo \~\]# \[\[ -v NAME \]

root@luo \~# echo $?

1

root@luo \~# NAME=1

root@luo \~\]# \[\[ -v NAME \]

root@luo \~# echo $?

0

root@luo \~#

语法规则: -R VAR 变量VAR是否被引用

示例:判断NAME变量是否被引用

root@luo \~# NAME=10

root@luo \~# test -v NAME

root@luo \~# echo $?

0

root@luo \~# test -R NAME

root@luo \~# echo $?

1

root@luo \~#

文件测试表达式

常用的文件测试操作符

-a/-e 文件 文件是否存在

-d 文件 文件存在且为目录则为真,即测试表达式成立

-f 文件 文件存在且为普通文件则为真,即测试表达式成立

-r 文件 文件存在且可读为真

-w 文件 文件存在且可写为真

-x 文件 文件存在且可执行则为真

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

root@luo \~# var_test='Mike'

root@luo \~# echo $var_test

Mike

root@luo \~# \[ -n var_test ] && echo "True"

True

通配符

root@luo \~# FILE=test.log

root@luo \~# \[ "$FILE" == \*.log ] && echo "True"

True

root@luo \~# FILE=test.txt

root@luo \~# \[ "$FILE" == \*.log ] && echo "True"

root@luo \~# \[ "$FILE" != \*.log ] && echo "True"

True

整数测试表达式***
或 test中使用的比较符号 在(()) 或 \[ ]中使用的比较符号(不用这个做数字比较) 说明
-eq \== 或 = 相等,equal
-ne != 不相等,not equal
-gt > 大于,greater than
-ge > = 大于等于,greater equal
-lt < 小于,less than
-le < = 小于等于,less equal
逻辑操作符
中使用的操作符 在test, \[ ] , (( ))中使用的逻辑操作符 说明
-a && and,与,两边都为真,则结果为真
-o || or,或,有真则真,同假则假
not,非,两端相反,则结果相反

root@luo \~# var_test=1

root@luo \~# var_t=2

root@luo \~\]# \[ $var_test -lt 0 -a $var_t -gt 0

root@luo \~# echo $?

1

root@luo \~\]# \[ $var_test -lt 0 -o $var_t -gt 0

root@luo \~# echo $?

0

关于()和 { } 的区别

shell中()与{}的区别是什么

  • ():在子shell中执行

  • {}:在当前shell中执行

( )和 { }都可以将多个命令组合再一次,批量执行,{ } 里的内容需要与两侧用空格隔开并在命令结尾加上 ;

  • ( )会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境***

    [root@server data]# name=luo
    [root@server data]# (echo name ; name=tong ; echo name );echo name luo tong luo [root@server data]# (echo name ; name=tong ; echo name ); luo tong [root@server data]# (echo name ; name=tong ; echo name );echo name
    luo
    tong
    luo

{ } 不会开启子shell,在当前shell中运行,会影响当前shell环境

注意使用{ }里的内容需要与两侧用空格隔开并在命令结尾加上 ;

name=luo;{ echo name ; name=tong ; echo name; };echo $name

复制代码
[root@server data]# name=luo;{ echo $name ; name=tong ; echo $name; };echo $name
luo
tong
tong
关于(( ))和\[ ]

在 Shell 脚本中,​​双括号 (( ))​​ 是 ​​算术运算和条件判断的核心语法结构​​,主要用于整数运算、逻辑表达式和变量操作。以下是其详细解析:

​​1. 核心功能​​

​​(1) 整数算术运算​​

​​支持运算符​​:加减乘除、取模、位运算、逻辑运算、自增/自减等。

#((a = 5 + 3 * 2)) #echo $a # 结果 11

#((b = 10 % 3)) #echo$b # 结果 1

#((c = 2 ** 3)) #echo $c # 结果 8(幂运算)

#((d = 10 >> 1)) #echo $d # 结果 5(右移1位)

((e++)) # 自增,e=6

((--f)) # 自减,f=9

​​引用​​:

​​(2) 数值比较与逻辑判断​​

​​支持 C 风格比较符​​:<, >, <=, >=, ==, !=。

​​逻辑运算符​​:&&(与), ||(或), !(非)。

if ((5 > 3 && 2 < 4)); then echo "条件成立"; fi # 输出结果

if ((a == 10 || b != 5)); then echo "逻辑成立"; fi

​​引用​​:

​​(3) 变量操作​​

​​无需 $ 前缀​​:直接使用变量名。

​​逗号分隔多表达式​​:以最后一个表达式的结果为最终值。

((x = 5, y = x * 2)) # x=5, y=10

echo $((x + y)) # 输出 15

​​引用​​:

​​2. 典型使用场景​​

​​(1) 数值计算​​

计算 1~100 的和

sum=0

for ((i=1; i<=100; i++)); do

((sum += i))

done

echo "总和: $sum" # 输出 5050

​​引用​​:

​​(2) 条件判断​​

num=10

if ((num % 2 == 0)); then

echo "偶数"

else

echo "奇数"

fi

​​引用​​:

​​(3) 自增/自减操作​​

count=0

echo $((count++)) # 输出 0,count 变为 1

echo $((--count)) # 输出 0,count 变为 0

​​引用​​:

​​3. 与其他括号的区别​​

括号类型 用途 示例 引用来源

(( )) 整数运算、逻辑判断 ((a=5+3))

(( )) 算术扩展(返回结果) echo ((5+3)) → 输出 8

\] 字符串/文件测试 \[ -f "file.txt"

\[ \]\] 高级条件判断(支持正则) \[\[ "abc" =\~ \^a \]

{ } 命令组、变量扩展 { echo a; echo b; }

组合测试条件

第一种方式

说明:-a 和 -o 需要使用测试命令执行,\[ ] 不支持

EXPRESSION1 -a EXPRESSION2 并且 ==> 条件1与条件2都为真,结果才为真

EXPRESSION1 -O EXPRESSION2 或 ==> 条件1与条件2只要有一个为真,结果就为真

!EXPRESSION1 取反

复制代码
[root@server ~]# touch 1.txt
[root@server ~]# file=/root/1.txt
[root@server ~]# [ -f 1.txt ]
[root@server ~]# echo $?            #是否存在的文件
0
[root@server ~]# ll 1.txt
-rw-r--r-- 1 root root 0 6月  20 16:17 1.txt
[root@server ~]# [ -f $file -a -x $file ]
[root@server ~]# echo $?            #是否存在的文件并且文件是否可执行
1
[root@server ~]# chmod +x 1.txt
[root@server ~]# ll 1.txt
-rwxr-xr-x 1 root root 0 6月  20 16:17 1.txt
[root@server ~]# [ -f $file -a -x $file ]
[root@server ~]# echo $?              #是否存在的文件并且文件是否可执行
0
[root@server ~]# [ ! -f $file -a -x $file ]
[root@server ~]# echo $?              #取相反的结果
1

[root@server ~]# [ ! -f $file -a -x $file ] && echo 111 || echo 222
222
[root@server ~]# [  -f $file -a -x $file ] && echo 111 || echo 222
111                #||是左边失败时执行右边,而&&是左边成功时执行右边
第二种方式\[ ]

COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN

如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2

COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE

如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2

! COMMAND #非,取反

结论:如果&& 和 || 混合使用,&&要在前,||放在后

复制代码
[root@server ~]# [ ! -f $file -a -x $file ] && echo 111 || echo 222
222
[root@server ~]# [  -f $file -a -x $file ] && echo 111 || echo 222
111

[root@ansible-salve1 ~]# id hehao &> /dev/null  || useradd hehao  # 前面执行不成功,则执行后面的语句
[root@ansible-salve1 ~]# id hehao &> /dev/null  && echo "此账户已存在"

# 查看磁盘空间占用率
[root@ansible-salve1 shell]# df | grep '^/dev/nv'  | grep -oE '[0-9]+%' | tr -d %
17
[root@ansible-salve1 shell]# cat fd.sh 
#!/bin/bash
WARNING=10
SPACE_USED=`df | grep '^/dev/nv'  | grep -oE '[0-9]+%' | tr -d %`
["$SPACE_USED" -gt $WARNING] && echo "磁盘空间不足,请尽快处理" |  mail -s "DISK Warning" 1446528135@qq.com

##反引号 ... 的本质是"用命令的执行结果代替自身"
#-e 选项会让 echo 识别并处理​​转义序列​​(以 \ 开头的特殊字符),将其转换为对应的控制字符或格式
#默认情况下(不使用 -e 选项),echo 会将输入的内容​​原样输出​​,包括反斜杠 \
read命令命令来接受输入
  • read -a 把读取的数据赋值给属组,从下标0开始
  • read -p 显示提示信息
  • read -s 静默模式,不显示输入的字符
  • read -n 读取n个字符,而不是整行字符

使用read给多个变量赋值并输出

复制代码
[root@server ~]# vim file.sh 
[root@server ~]# chmod +x file.sh 
[root@server ~]# bash file.sh
请输入你的年龄,性别,身高:19 nan 180
你的年龄是:19
你的性别是:nan
你的身高是:180
[root@server ~]# cat file.sh 
#!bin/bash
read -p "请输入你的年龄,性别,身高:" nianling xingbie shengao
echo "你的年龄是:$nianling"
echo "你的性别是:$xingbie"
echo "你的身高是:$shengao"

read -n 只读取一个字符

复制代码
# -n 1表示只读取一个字符,运行脚本后,只要用户输入一个字符,立即就读取结束,不等待用户按下回车键
[root@ansible-salve1 shell]# vim info1.sh 
#!/bin/bash
read -n 1 -p "Enter a char > " char  && printf "\n"
echo "---------------------------------------------------------"
echo $char
[root@ansible-salve1 shell]# chmod +x info1.sh 
[root@ansible-salve1 shell]# ./info1.sh 
Enter a char > a
---------------------------------------------------------
a

流程控制

条件选择

选择执行if语句

多个if条件时,逐个条件进行判断,第一次遇见为"真"条件时,执行其分支,而后结束整个if语句

复制代码
if结构:
[root@ansible-salve1 shell]# help if
if: if 条件; then 命令; [ elif 命令; then 命令; ]... [ else 命令; ] fi
    根据条件执行命令。
    
    `if COMMANDS'列表被执行。如果退出状态为零,则执行`then COMMANDS' 
    列表。否则按顺序执行每个 `elif COMMANDS'列表,并且如果它的退出状态为
    零,则执行对应的 `then COMMANDS' 列表并且 if 命令终止。否则如果存在的
    情况下,执行 `else COMMANDS'列表。整个结构的退出状态是最后一个执行
    的命令的状态,或者如果没有条件测试为真的话,为零。
    
    退出状态:
    返回最后一个执行的命令的状态。
[root@ansible-salve1 shell]# 

if 结构是​​条件控制​​的核心语法,用于根据条件是否成立执行不同的代码块。以下是 if 结构的详细解析,涵盖基本语法、逻辑操作符、文件测试、字符串比较等常见用法。

​​1. 基础 if 结构​​
​​(1) 基本语法​​
if [ 条件 ]; then
    # 条件为真时执行的命令
fi
[ 条件 ] 是测试表达式(注意 [ 和 ] 两侧必须有空格!)。
then 标记条件成立后的代码块起始。
fi 表示 if 结构结束(必须存在,否则语法错误)。
​​示例​​:

if [ "$USER" = "root" ]; then
    echo "当前用户是 root"
fi
​​(2) if-else 结构​​
if [ 条件 ]; then
    # 条件为真时执行
else
    # 条件为假时执行
fi
​​示例​​:

if [ -f "/etc/passwd" ]; then
    echo "文件存在"
else
    echo "文件不存在"
fi
​​(3) if-elif-else 结构(多条件分支)​​
if [ 条件1 ]; then
    # 条件1为真时执行
elif [ 条件2 ]; then
    # 条件2为真时执行
else
    # 所有条件均为假时执行
fi
​​示例​​:

if [ "$1" = "start" ]; then
    echo "启动服务"
elif [ "$1" = "stop" ]; then
    echo "停止服务"
else
    echo "无效参数,请使用 start/stop"
fi
条件判断case语句

注意:双 ; ; 号结尾

复制代码
case 变量引用 in
PAT1)
	分支1
	;;
PAT2)
	分支2
	;;
...
*)
	默认分支
	;;
esac

[root@ansible-salve1 shell]# vim info6.sh 
#!/bin/bash
read -p "Do you agree(yes/no)?" INPUT

INPUT=`echo $INPUT | tr 'A-Z' 'a-z'`

case $INPUT in
y|yes)  
        echo "You input is Yes"
        ;;
n|no)
        echo "You input is No"
        ;;
*)      
        echo "Input fales,please input yes or no!"
esac  
[root@ansible-salve1 shell]# chmod +x info6.sh
[root@ansible-salve1 shell]# ./info6.sh 
Do you agree(yes/no)?yes
You input is Yes
[root@ansible-salve1 shell]# ./info6.sh 
Do you agree(yes/no)?no
You input is No
[root@ansible-salve1 shell]# ./info6.sh 
Do you agree(yes/no)?111
Input fales,please input yes or no!
[root@ansible-salve1 shell]# 

循环

将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件

重复运行次数

  • 循环次数事先已知

  • 循环次数事先未知

常见的循环的命令:for,while

复制代码
#循环的逻辑:程序先进行语句判断,如果为真则执行循环语句,然后再进行语句判断,直至语句判断失败才跳出
for循环

格式1:

第一种写法

for NAME in words ...; do commands;done

第二种写法

for 变量 in 列表

循环体

done

第三种写法

for 变量 in 列表

do

循环体

done

复制代码
for 循环用于​​遍历固定列表中的元素​​,逐个处理每个元素,适合已知迭代次数或明确列表的场景。

​​1. 基础语法​​
for 变量 in 列表; do
    # 对每个元素执行的代码块
done
列表:可以是空格分隔的字符串、命令输出、数组元素等。
变量:每次循环中依次取列表中的一个元素赋值。
​​2. 典型用法​​
​​(1) 遍历固定列表​​
for fruit in apple banana orange; do
    echo "我爱吃 $fruit"
done
​​输出​​:

我爱吃 apple
我爱吃 banana
我爱吃 orange
​​(2) 遍历命令输出​​
通过 $(command) 或反引号获取命令输出,逐行处理(注意:默认按空格分割,若需按行分割需设置 IFS):

# 遍历当前目录下的文件(按空格分割)
for file in $(ls); do
    echo "文件:$file"
done

# 按行遍历文件内容(设置 IFS=$'\n')
IFS=$'\n'
for line in $(cat /etc/passwd); do
    echo "行内容:$line"
done
​​(3) 遍历数组​​
arr=("北京" "上海" "广州" "深圳")
for city in "${arr[@]}"; do 		 # "${arr[@]}" 展开为所有数组元素
    echo "城市:$city"
done
​​(4) C风格循环(类似 for(i=0;i<10;i++))​​
Bash 支持类似 C 语言的 for 循环语法(需用 (( )) 算术表达式):

for ((i=0; i<5; i++)); do
    echo "第 $i 次循环"
done
​​输出​​:

第 0 次循环
第 1 次循环
第 2 次循环
第 3 次循环
第 4 次循环

格式2:

双小括号方法,即((...))格式,也可以用于算术运算,双小括号方法也可以使用bash shell 实现C语言风格的变量操作l=10;((l++))

for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))

do

循环体

done

说明:

  • 控制变量初始化:仅在运行到循环代码段时执行一次

  • 控制变量的修正表达式:每轮循环结束后会先进行控制变量修正运算,然后在做条件判断

while循环

while: while 命令; do 命令; done

只要测试成功即执行命令。

只要在 `while' COMMANDS 中的最终命令返回结果为0,则

展开并执行 COMMANDS 命令。

退出状态:

返回最后一个执行的命令的状态。

condition:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为"Ture",则执行一次循环;直到条件测试状态为"false"终止循环,因此:condition一般应该有循环控制变量;而此变量的值会在循环不断地被修正

格式:

无限循环

while true;do

循环体

done

复制代码
while:条件循环​​
while 循环用于​​根据条件表达式的真假重复执行代码块​​,直到条件为假为止,适合未知迭代次数或依赖动态条件的场景。

​​1. 基础语法​​
while 条件表达式; do
    # 条件为真时执行的代码块
done
条件表达式:与 if 语句中的条件相同(返回布尔值)。
​​2. 典型用法​​
​​(1) 基于计数的循环​​
count=0								#count中文总数
while [[ $count -lt 5 ]]; do
    echo "计数:$count"
    ((count++))  # 等价于 count=$((count + 1))
done
​​输出​​:

计数:0
计数:1
计数:2
计数:3
计数:4
​​(2) 读取输入逐行处理​​
结合 read 命令读取文件或标准输入的每一行:

# 读取文件每一行
while IFS= read -r line; do  # -r 禁止反斜杠转义,IFS= 保留行首尾空格
    echo "处理行:$line"
done < input.txt

# 读取标准输入(交互式)
echo "输入内容(输入 exit 退出):"
while read -r input; do
    if [[ $input == "exit" ]]; then			
        break  # 退出循环
    fi
    echo "你输入了:$input"
done
read -r input 是 Shell 中用于​​从标准输入(如键盘或管道)读取一行内容​​到变量 input 的命令,其中:
-r:禁止反斜杠转义(raw mode),确保输入内容原样读取。
input:存储读取内容的变量名(可自定义)
​​(3) 监控进程或资源​​
持续检查进程是否运行,直到退出:

pid=1234  # 目标进程 ID
while ps -p $pid > /dev/null; do  # ps -p 检查进程是否存在    ps -p 1234 查看PID为1234的进程
    echo "进程 $pid 正在运行..."
    sleep 1 					 # 每秒检查一次
done
echo "进程 $pid 已退出"
​​3. 扩展:until 循环​​
until 是 while 的反向逻辑,​​当条件为假时继续执行,直到条件为真时退出​​(适合"等待直到满足条件"的场景):

count=0
until [[ $count -ge 5 ]]; do  # 当 count >=5 时退出循环
    echo "计数:$count"
    ((count++))
done
​​输出​​与 while 示例相同。

​​4. 注意事项​​
​​无限循环​​:若条件始终为真(如 while true; do ...),需通过 break 或 exit 退出。
​​break 和 continue​​:
break:退出当前循环,继续执行循环后的代码。
continue:跳过当前循环的剩余代码,直接进入下一次循环。
​​五、总结:如何选择?​​
​​语句​​	​​适用场景​​
if	单条件或多条件分支判断(根据条件选择执行路径)。
case	多模式匹配(如参数、文件扩展名、固定字符串模式)。
for	遍历已知列表(固定元素、命令输出、数组),或已知迭代次数(C风格循环)。
while	未知迭代次数,依赖动态条件(如监控资源、读取输入直到特定条件)。
循环控制语句

continue

continueN:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层

复制代码
for (());do
     循环体1
     ...
     if command2;then
         continue
     fi
     CMDn
     ....
done

break

breakN:提前结束第N层后的全部循环;最内层为第1层,默认为1

案例:持续监控应用状态

复制代码
#!/bin/bash
#Fuction:基于While循环持续监控应用状态
while true
do
    if systemctl status sshd | grep -q "active (running)";then
        break
    fi
    sleep 10
done

Shell数组的概念

数组是若干数据的集合,其中存放的每一份数据都称为元素。Shell不限制数组的大小,理论上可以存放无限量的数据,Shell数组元素的下标也是从0开始计数

获取数组中的元素要使用下标 ,下标可以是一个整数,也可以是一个结果为整数的表达式;下标必须大于等于0

注意:Shell只支持一维数组,不支持多维数组

Shell中,用小括号()来表示数组,数组元素之间用空格来分隔

复制代码
#arrayname=(1 2 3 4 5)
`输出定义数组中的全部元素
#echo ${arrayname[*]}
#echo ${arrayname[@]}
`输出定义数组中的第一个元素
#echo ${arrayname[0]}
`输出定义数组中的第二个元素
#echo ${arrayname[1]}
`输出定义数组中的元素个数
#echo ${#arrayname[*]}

[root@server ~]# name=(1 2 3 4)
[root@server ~]# echo ${name[*]}
1 2 3 4
[root@server ~]# echo ${name[@]}
1 2 3 4
[root@server ~]# echo ${name[0]}
1
[root@server ~]# echo ${name[2]}
3
[root@server ~]# echo ${#name[*]}
4
采用键值对的形式赋值

Shell中用小括号将变量括起来,同时采用键值对的形式赋值

#array2=(1=one 2=two 3=three)

echo ${array2\*} #输出定义数组的所有元素

echo ${array2@} #输出定义数组的所有元素

echo ${#array2@} #输出定义数组的元素个数

复制代码
[root@server ~]# name=([1]=a [2]=b [3]=c)
[root@server ~]# echo ${name[*]}
a b c
[root@server ~]# echo ${name[@]}
a b c
[root@server ~]# echo ${#name[@]}
3
动态定义数组数量
复制代码
root@server ~]# mkdir -p /array/aaa
[root@server ~]# cd /array/aaa
[root@server aaa]# ls
[root@server aaa]# touch f{1..4}.txt
[root@server aaa]# ll
总用量 0
-rw-r--r-- 1 root root 0 6月  20 20:24 f1.txt
-rw-r--r-- 1 root root 0 6月  20 20:24 f2.txt
-rw-r--r-- 1 root root 0 6月  20 20:24 f3.txt
-rw-r--r-- 1 root root 0 6月  20 20:24 f4.txt
[root@server aaa]# name=($(ls aaa))
ls: 无法访问aaa: 没有那个文件或目录
[root@server aaa]# name=($(ls /aaa))
ls: 无法访问/aaa: 没有那个文件或目录
[root@server aaa]# cd
[root@server ~]# name=($(ls /array/aaa))
[root@server ~]# echo ${name[*]}
f1.txt f2.txt f3.txt f4.txt
[root@server ~]# echo ${name[@]}
f1.txt f2.txt f3.txt f4.txt
[root@server ~]# echo ${#name[*]}
4

hell数组的打印

  • 打印单个数组元素: ${数组名下标} 。当未指定数组下标时,下标默认从0开始

  • 打印全部数组内容:{数组名\[@\]}或 {数组名\*}

  • 打印数组元素的个数:{#数组名\[@\]}或 {#数组名\*}

Shell数组的赋值

如果下标不存在,则自动添加一个新的元素;如果下标存在,则覆盖原来的值

Shell数组的拼接合并

所谓Shell数组拼接(数组合并),就是将两个数组连接成一个数组

拼接数组的思路是:先利用@或者*,将数组扩展成列表,然后再合并到一起,具体格式如下:

复制代码
array_new=(${array1[@]} ${array2[@]})
array_new=(${array1[*]} ${array2[*]})
`两种方式是等价的,选择其一即可。其中,array1 和 array2 是需要拼接的数组,array_new 是拼接后形成的新数组。

示例:

复制代码
#!/bin/bash
array1=(1 2 3 4 5)
array2=("https://www.baidu.com" "https://www.hehao.online" "https://www.taobao.com")
array_new=(${array1[*]} ${array2[*]})
echo ${array_new[@]}
​
--->结果
1 2 3 4 5 https://www.baidu.com https://www.hehao.online https://www.taobao.com

Shell删除数组元素

Shell中,使用unset关键字来删除数组元素,具体格式如下:

复制代码
unset array_name[index]
`其中,array_name表示数组名,index表示数组下标
​
unset array_name 
`删除整个数组

获取数组某范围的元素

Shell中直接通过${数组名[@/*]:起始位置:长度}获取数组给定范围内元素,返回字符串,中间用空格分开

复制代码
#!/bin/bash
array=(yoona lucy tom)
echo ${array[*]}
echo ${array[*]:1:2}
echo ${array[@]:0:2}
-->结果为:
yoona lucy tom
lucy tom
yoona lucy

数组元素的替换

${数组名[@/*]/查找字符/替换字符}该操作不会改变原先数组内容,如果需要修改,使用覆盖

复制代码
#!/bin/bash
array=(yoona lucy tom)
echo ${array[@]/lucy/lily}
echo ${array[*]}
​
--->结果为:
yoona lily tom
yoona lucy tom

Shell函数的定义

Shell函数的本质是一段可以重复使用的脚本代码,这段代码被提前编好了,放在了指定位置,使用时直接调用即可

Shell 中的函数和C++、Java、Python、C# 等其它编程语言中的函数类似,只是在语法细节有所差别。

Shell 函数定义的语法格式如下:

复制代码
function name() {
  statements
  [return value]
}

带function关键字

function greet() {

echo "Hello!"

}

省略function关键字

greet2() {

echo "Hi!"

}

对各个部分的说明:

  • function是 Shell 中的关键字,专门用来定义函数;

  • name是函数名;

  • statements是函数要执行的代码,也就是一组语句;

  • return value表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。

{ }包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。

函数定义的简化写法

复制代码
1.
name() {
    statements
    [return value]
}
2.
function name() {
    statements
    [return value]
}

Shell函数的调用

调用 Shell 函数时可以给它传递参数,也可以不传递。如果不传递参数,直接给出函数名字即可:

复制代码
name

如果传递参数,那么多个参数之间以空格分隔:

复制代码
name param1 param2 param3

不管是哪种形式,函数名字后面都不需要带括号。

和其它编程语言不同的是,Shell 函数在定义时不能指明参数,但是在调用时却可以传递参数,并且给它传递什么参数它就接收什么参数。

Shell函数详解

Shell中的函数在定义时不能指明参数,但是在调用时却可以传递参数。函数参数是Shell位置参数的一种,在函数内部可以使用$n来接收,例如:$1表示第一个参数,$2表示第二个参数,依次类推

除了$n,还有另外三个比较重要的变量:

  • $#可以获取传递的参数的个数;

  • $@或者$*可以一次性获取所有的参数

扩展:在Shell中 @与*的区别

复制代码
在Shell脚本中,$*和$@是Shell脚本的特殊变量,作用都是获取传递给脚本或函数的所有参数
​
$@与$*的相同点:当它们没有被双引号包裹时,两者是没有区别的,都代表一个包含接收到的所有参数的数组,各个数组元素都是传入的独立参数
​
$@与$*的不同点:当被双引号包裹时,$@仍为一个数组,而$*会将所有参数整合成一个字符串

案例1:计算两个数的和(带用户输入)

cs 复制代码
#!/bin/bash
# 定义加法函数
add() {
    sum=$(( $1 + $2 ))  # 使用$1、$2获取参数
    echo "两数之和为: $sum"
}

# 调用函数并传递参数
read -p "请输入第一个数: " num1
read -p "请输入第二个数: " num2
add $num1 $num2  # 输出:两数之和为: 结果值

​特点​​:

  • 使用$1$2接收参数

    1

  • 通过echo返回结果(替代return

    1

  • 结合read实现用户交互


案例2:判断数字是否为正数

复制代码
cs 复制代码
#!/bin/bash
# 定义判断函数
is_positive() {
    if [ $1 -gt 0 ]; then
        echo "yes"
    else
        echo "no"
    fi
}

# 调用函数并获取返回值
result=$(is_positive -5)  # 输出:no
echo "结果: $result"

​特点​​:

  • 使用if条件判断

    7

  • 通过$?获取函数退出状态码(0表示成功)

    7

  • 演示函数返回值的两种方式


案例3:统计文件行数(带参数)

cs 复制代码
#!/bin/bash
# 定义统计函数
count_lines() {
    local file=$1  # 局部变量避免冲突
    wc -l < "$file"  # 使用重定向避免输出文件名
}

# 调用函数
lines=$(count_lines example.txt)
echo "文件行数: $lines"

​特点​​:

  • 使用local声明局部变量

    1

    7

  • 文件操作实战

  • 命令替换$(...)获取输出


案例4:批量重命名文件(实用场景)

cs 复制代码
#!/bin/bash
# 定义重命名函数
rename_files() {
    for file in *.txt; do
        mv "$file" "new_$file"  # 在原文件名前加"new_"
    done
}

# 执行函数
rename_files

​特点​​:

  • 循环处理多个文件 3

  • 字符串拼接操作

  • 文件批量操作实战

相关推荐
zcmodeltech11 分钟前
智能矿井沙盘模型多系统协同控制系统设计:基于STM32与Modbus RTU的感知-传输-控制一体化方案
服务器·数据库·分布式·stm32·单片机·嵌入式硬件
江湖有缘22 分钟前
Docker实战 | 使用Docker部署Donetick任务与家务管理应用
运维·docker·容器
实心儿儿31 分钟前
Linux —— 应用层协议HTTP
linux·网络·http
流星白龙35 分钟前
【Docker】4.NameSpace空间隔离实战
java·运维·docker
有续技术1 小时前
哈斯 (Haas) 机床 IP、端口号配置内容总结
运维·服务器
小张同学a.2 小时前
LAMP架构2
linux·运维·网络·架构·负载均衡
千河殇 多想和她2 小时前
如何在Reaonix中使用CodeGraph以及CodeGraph效果实测经验分享
linux·运维·ubuntu
VortMall2 小时前
出海引流运维双升级|VortMall微服务商城系统v1.3.12 升级更新
运维·微服务·facebook
心念枕惊2 小时前
新写了个直播录制工具,可录制抖音快手斗鱼直播
运维·服务器·数据库
躺不平的理查德2 小时前
CMAKE备忘录
linux·运维·服务器