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" [email protected]

##反引号 ... 的本质是"用命令的执行结果代替自身"
#-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

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

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

break

break[N]:提前结束第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

  • 字符串拼接操作

  • 文件批量操作实战

相关推荐
Java小白笔记3 分钟前
Linux中使用grep查看日志
linux·运维·服务器
靡樊22 分钟前
传输层协议UDP/TCP
linux·网络·网络协议·学习·tcp/ip·udp
Hat_man_43 分钟前
Windows下memcpy_s如何在Linux下使用
linux·c++
WW、forever1 小时前
【服务器R环境架构】基于 micromamba下载 R 库包
运维·服务器·r语言
在成都搬砖的鸭鸭1 小时前
【Linux】network网络配置
linux·服务器·网络
程序员Xu1 小时前
Vulkan学习笔记10—统一缓冲区
服务器·笔记·学习
Xの哲學1 小时前
hostapd 驱动注册机制深度分析
linux·网络·算法·wireless
海海不掉头发1 小时前
【2025 年】软件体系结构考试试卷-期末考试
java·服务器·软件体系结构
广目软件1 小时前
GM DC Monitor v2.0 卸载教程
服务器·网络·zabbix·prometheus
baidu_195527872 小时前
qt集成openssl
运维·qt