目录
[、 Shell脚本基本结构:](#、 Shell脚本基本结构:)
[、 脚本注释规范](#、 脚本注释规范)
[、 变量定义和引用](#、 变量定义和引用)
[4.1 算数运算](#4.1 算数运算)
[4.2 Bash中的算术运算](#4.2 Bash中的算术运算)
[4.2 实现算术运算](#4.2 实现算术运算)
[关于()和 { } 的区别](#关于()和 { } 的区别)
[关于(( ))和[[ ]]](#关于(( ))和[[ ]])
[第一种方式[ ]](#第一种方式[ ])
[第二种方式[[ ]]](#第二种方式[[ ]])
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编程中最常用的数据类型之一
字符串可以由单引号''
包围,也可以由""
包围,也可以不用引号,三种方式的区别
-
由单引号
' '
包围的字符串-
任何字符都会原样输出,在其中使用变量是无效的
-
字符串中不能出现单引号,即使对单引号进行转义也不行
-
-
由双引号
" "
包围的字符串-
如果其中包含了某个变量,那么该变量就会被解析(得到该变量的值),而不是原样输出
-
字符串中可以出现双引号,只要进行转义就行
-
-
不被引号包围的字符串
-
不被引号包围的字符串中出现变量也会被解析,这一点和双引号
""
包围的字符串一样 -
字符串中不能出现空格,否则空格后面的字符串会作为其他变量或者命令解析
-
通过代码演示一下三种形式的区别
#!/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
-
字符串拼接操作
-
文件批量操作实战