linux-shell脚本
- 一、什么是shell脚本?
- 二、为什么要学习shell脚本?
- 三、脚本执行的方式
- 3.1 bash test.sh
- 3.2 ./test.sh
- 3.3 source test.sh
- 3.4 . test.sh
- 四、变量的使用
- 4.1 变量定义与使用
- 4.2 避免变量混淆
- 4.3 位置变量
- for循环和位置变量的结合案例
- 4.4 read
- 五、流程控制
- 5.1 条件判断:if-else结构
- 5.1.1 基本语法
- 5.1.2 条件测试
- 5.2 case多分支
- 5.3 for循环
- 5.4 while循环
- while 死循环
- 算术表达式错误
- 1. 赋值为字符串
- 2. 使用正则表达式
- 六、命令替换
- 七、 函数
- 1. 函数定义与使用
- 2. 函数嵌套和变量的作用域问题
- 八、数组
- 总结
一、什么是shell脚本?
脚本:script
: 一般是编程语言的文件,里面有很多的命令
本质上是一个文件,用来实现某个或者某些功能–》就是一个程序
输入linux命令 --》shell --》解释命令、查找命令、运行命令
shell编程—》linux里的命令编程–》把很多命令存放到一个文件里,可以用来实现很多的功能,这个文件就叫shell脚本
#!/bin/bash
--》声明解释器使用的是/bin/bash 默认
[root@localhost shell]# cat /etc/shells 查看linux系统支持哪些shell
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
[root@localhost shell]# echo $SHELL 查看默认的shell是哪个
/bin/bash # binary 二进制
[root@localhost shell]# env
SHELL=/bin/bash
shell脚本的执行顺序,从上而下,如果中间的某条命令执行出错,后面的命令是否执行?
默认会执行,直到脚本的末尾
[root@localhost shell]# vim test.sh
set -e # 告诉shell解释器,一旦某条命令执行出错,立马退出当前shell,停止执行后面的命令
#!/bin/bash
for i in {1..10}
doif id feng\$i &>/dev/null;thenecho "feng\$i 已经存在" elseuseradd feng\$i && echo "新建 feng\$i 用户成功"fi
done
echo "新建10个用户成功"
fjdkfjdkj
echo "ok"
二、为什么要学习shell脚本?
- 自动化任务:减少重复性工作(如备份、部署、日志分析)。
- 系统管理:批量处理文件、监控服务器状态、配置环境。
- 效率提升:快速验证想法,避免手动输入大量命令。
- 兼容性:几乎所有 Linux/Unix 系统都支持,无需额外安装。
- 轻量级:无需编译,直接运行,适合快速开发。
- 集成工具:可调用其他程序(如 Python、grep、awk),扩展功能。
- 求职需求:运维、开发工程师必备技能,提升竞争力。
三、脚本执行的方式
在当前终端里产生一个子bash进程去执行test.sh
[root@hz shell]# vim test.sh
#!/bin/bash
echo “$bigcity $num1”
i=1
echo $i
echo “end”
[root@hz shell]# bigcity=“shanghai”
[root@hz shell]# num1=3000
[root@hz shell]# ll test.sh
-rw-r–r–. 1 root root 59 6月 26 20:17 test.sh
3.1 bash test.sh
[root@hz shell]# bash test.sh
1
end
[root@hz shell]# export bigcity num1 # 输出变量为全局变量
[root@hz shell]# bash test.sh
shanghai 3000
1
end
3.2 ./test.sh
必须提前授予可执行权限 chmod +x test.sh
[root@hz shell]# ./test.sh
-bash: ./test.sh: 权限不够
[root@hz shell]# chmod +x test.sh
[root@hz shell]# ll test.sh
-rwxr-xr-x. 1 root root 59 6月 26 20:17 test.sh
[root@hz shell]# ./test.sh
1
end
3.3 source test.sh
在当前终端里(bash)去执行test.sh
[root@hz shell]# source test.sh
shanghai 3000
1
end
3.4 . test.sh
在当前终端里(bash)去执行test.sh
[root@hz shell]# . test.sh
shanghai 3000
1
end
四、变量的使用
4.1 变量定义与使用
[root@localhost feng]city=changsha
[root@localhost feng]echo $city
changsha
# shell编程,变量不定义可以直接使用
[root@localhost feng]# echo $CITY
[root@localhost feng]#
如果变量不定义,默认的值就是空值
4.2 避免变量混淆
可以使用{}
单独标识一个变量,这样shell在解析命令的时候,就知道是一个单独的变量了,不会和其他的字符拼接成一个新的变量
[root@hz shell]# filename=“sc”
[root@hz shell]# touch $filename{1. .10}.txt
[root@hz shell]# ls
[root@hz shell]# echo $filename{1. .10}.txt
.txt .txt .txt .txt .txt .txt .txt .txt .txt .txt
[root@hz shell]# echo $filename1
[root@hz shell]# echo $filename
sc
[root@hz shell]# echo $(filename)1
-bash: filename:未找到命令
1
[root@hz shell]# echo ${filename}1
sc1
[root@hz shell]# echo $filename-1
sc-1
[root@hz shell]# echo $filename_1
[root@hz shell]# echo ${filename}_1
sc_1
4.3 位置变量
传参 position variable
[root@hz shell]# vim position_var.sh
#!bin/bsah
echo “第1个位置变量是:$1”
echo “第2个位置变量是:$2”
echo “第3个位置变量是:$3”
echo “第4个位置变量是:$4”
echo “脚本名字是:$0”
echo “一共有$#个位置变量”
echo “所有的位置变量:$@”
echo “所有的位置变量$*”
useradd $1
useradd $2
[root@hz shell]# bash position_var.sh shengyuran pengyaqin zhenglu caojie luobiao
第1个位置变量是:shengyuran
第2个位置变量是:pengyaqin
第3个位置变量是:zhenglu
第4个位置变量是:caojie
脚本名字是:position_var.sh
一共有5个位置变量
所有的位置变量:shengyuran pengyaqin zhenglu caojie luobiao
所有的位置变量shengyuran pengyaqin zhenglu caojie luobiao
[root@hz shell]# id shengyuran
用户id=1026(shengyuran) 组id=1026(shengyuran) 组=1026(shengyuran)
[root@hz shell]# id pengyaqin
用户id=1027(pengyaqin) 组id=1027(pengyaqin) 组=1027(pengyaqin)
[root@hz shell]# id caoajie
id: “caoajie”:无此用户
for循环和位置变量的结合案例
[root@hz shell]# vim for.sh
#!/bin/bash
for username in $@
douseradd $username
done
echo "for循环执行完毕"# 批量创建用户,使用位置变量进行传参
[root@hz shell]# bash for.sh caojie luobiao zouqiang zhenglu shengyuran pengyaqin
useradd:用户“zhenglu”已存在
useradd:用户“shengyuran”已存在
useradd:用户“pengyaqin”已存在
for循环执行完毕
改进
[root@hz shell]# vim for.sh
#!/bin/bash
for username in $@
doif id $username &>/dev/null;thenecho "\$username 用户已经存在"echo "123456"|passwd \$username --stdinelseecho "$username 用户不存在,立马进行新建操作"useradd $username && echo "123456"|passwd $username --stdinfi
done
echo "for循环执行完毕"[root@hz shell]# bash for.sh shengyuran caojie panmingqian rose jack
shengyuran 用户已经存在
更改用户 shengyuran 的密码 。
passwd:所有的身份验证令牌已经成功更新。
caojie 用户已经存在
更改用户 caojie 的密码 。
passwd:所有的身份验证令牌已经成功更新。
panmingqian 用户已经存在
更改用户 panmingqian 的密码 。
passwd:所有的身份验证令牌已经成功更新。
rose 用户不存在,立马进行新建操作
更改用户 rose 的密码 。
passwd:所有的身份验证令牌已经成功更新。
jack 用户不存在,立马进行新建操作
更改用户 jack 的密码 。
passwd:所有的身份验证令牌已经成功更新。
for循环执行完毕
生成随机密码
[root@hz shell]# echo $RANDOM|sha256sum|cut -c1-10 # -c 截取字符串 character
a478bbad4f
[root@hz shell]# echo $RANDOM|md5sum|cut -c1-10
2d636621c5
for循环批量创建用户并生成随机密码
[root@hz shell]# cat create_user.sh
#!/bin/bash
for username in "$@"
doif id $username &>/dev/null;then# 产生随机密码u_passwd=$(echo RANDOM|sha256sum|cut -c1-10)echo "$username:$u_passwd"|chpasswd# 保存用户名和密码到文件里echo "username:$username password:$u_passwd" >>user_password.txtelse# 产生随机密码u_passwd=$(pwgen -s -y 10 1)echo "$username:$u_passwd"|chpasswd# 保存用户名和密码到文件里echo "username:$username password:$u_passwd" >>user_password.txtfi
done[root@hz shell]# bash create_user.sh caojie luobiao hubiwu tom
chpasswd:第 1 行:用户“hubiwu”不存在
chpasswd:发现错误,忽略改动
chpasswd:第 1 行:用户“tom”不存在
chpasswd:发现错误,忽略改动[root@hz shell]# cat user_password.txt
username:caojie password:7300a197d7
username:luobiao password:7300a197d7
username:hubiwu password:_,MpB$3]&\
username:tom password:-:B#BZ6v-`
4.4 read
适合交互式
将用户输入的内容赋值变量
[root@hz shell]# read -p “请输入你的用户名:” username promt 提示
请输入你的用户名:li
[root@hz shell]# echo $username
li
[root@hz shell]# read num1 num2 num3
10 20 30
[root@hz shell]# echo $num1 $num2 $num3
10 20 30
read设置用户和密码
[root@hz shell]# vim read.sh
#!/bin/bash
read -p "请输入用户名:" username
read -p "请输入你的密码:" u_passwduseradd $username
echo $u_passwd|passwd $username --stdinecho "#####################"
read -p "请输入你的选择:" choice# || 表示前面的条件或后面的条件只要满足一个就可以了,逻辑或 or
if [[ $choice == "y" || $choice == "Y" ]];thenecho "你的选择是执行 yes"
elseecho "你的选择是不执行 no"
fi[root@hz shell]# bash read.sh
请输入用户名:j
请输入你的密码:123456
更改用户 j 的密码 。
passwd:所有的身份验证令牌已经成功更新。
#####################
请输入你的选择:y
你的选择是执行 yes
五、流程控制
5.1 条件判断:if-else结构
对某种情况进行判断 如果
5.1.1 基本语法
单分支:只有一种情况
双分支:2种情况 else
if
命令1;then
命令2
else
命令3
fi
多分支:多种情况
字符串的判断:使用双中括号 --》支持字符串里有空格
[root@hz shell]# sg=“admin”
[root@hz shell]# [[ $sg == “feng” ]]
[root@hz shell]# echo $?
1
[root@hz shell]# [[ $sg == “admin” ]]
[root@hz shell]# echo $?
0
[root@hz ~]# sg=“ad min”
[root@hz ~]# [ $sg == “admin” ]
-bash: [: 参数太多
[root@hz ~]# sg=“admin”
[root@hz ~]# [ $sg == “admin” ]
[root@hz ~]# echo $?
0
;
命令连接符号
command1 ; command2
先执行第1个命令,然后去执行第2个命令 ,无论第一个命令执行是否成功,都会执行第二个命令
# 对if进行说明,if会自动去拿命令执行后的返回值
if[[ $? == 0 ]];thencommand
fiif[[ $? == 0 ]]
thencommand
fi
if-else
示例
[root@hz ~]# vim test.sh
#!/bin/bashmkdir -p /zou99
cd /zou99
touch zou{1..10}.txt
sg="zou123"
mkdir $sg
cd $sg
ls
# 对if进行说明,if会自动去拿命令执行后的返回值
if [[ $? != 0 ]];thenecho"上一条命令执行失败"exit # 退出
elseecho"继续执行下面的命令"
fiecho "###############"
pwd
cp /etc/hosts .
mv hosts z_hosts
touch sc.txt sc1.txt
rm -rf sc.txt
echo "脚本执行完成"[root@hz ~]# bash test.sh
sc1.txt z_hosts
继续执行下面的命令
###############
/zou99/zou123
脚本执行完成
5.1.2 条件测试
- 文件测试
[ -e file ]
判断文件是否存在 exist
[ -d file ]
判断文件是否存在且是否为目录 directory
[ -f file ]
判断文件是否存在且是否为文件 file
[ -w file ]
判断文件是否存在且是否为可写文件 write
[ -x file ]
判断文件是否存在且是否为可执行文件 execute
[ -r file ]
判断文件是否存在且是否为可读文件 read
[ -s file ]
判断文件是否存在且是否为非空文件 size
[]
和 test
功能一样,如 test -e /etc/passwd
- 数值比较
推荐使用双圆括号
[ int1 -gt int2 ] ((int1>int2)) greater than 大于
[ int1 -ge int2 ] ((int1>=int2)) greater equal 大于等于
[ int1 -eq int2 ] (( int1=int2 )) equal 等于
[ int1 -ne int2 ] (( int1!=int2 )) not equal 不等于
[ int1 -le int2 ] (( int1<=int2 )) less equal 少于等于
[ int1 -lt int2 ] (( int1<int2 )) less than 少于
小数比较用bc
[root@rocky ~]# echo “4.8 > 3”|bc
1
[root@rocky ~]# echo “4.8 > 5”|bc
0
- 字符串比较
[ "$a" = "$b" ]
相等
[ "$a" != "$b" ]
不相等
[ -n "$a" ]
和 [ "$a" ]
一样 判断字符串$a长度是否大于0
[ -z $a ]
判断$a 的长度是否为0
[[ "$a" == *"redhat"* ]]
判断在$a中是否含有redhat字符串
- 逻辑组合
&&
(与) 、||
(或)、!
(非)
命令1 && 命令2 --》如果命令1执行成功,就执行命令2
命令1 || 命令2 --》如果命令1执行不成功,就执行命令2
命令1 && 命令2 || 命令3 --》如果命令1执行成功,就执行命令2,不成功执行命令3
[root@hz shell]# fjdk && echo “ok”
-bash: fjdk:未找到命令
[root@hz shell]# fjdk || echo “ok”
-bash: fjdk:未找到命令
ok
[root@hz shell]# fjdk && echo “ok” || echo “no”
-bash: fjdk:未找到命令
no
示例
[root@hz shell]vim create _file.sh
#!/bin/bash# 定义变量filename
filename="feng"mkdir -p /backup
cd /backup
touch ${filename}{1..100}.txt
mkdir -p hunan beijing shanghai[ -d hunan ] && echo "hunan文件夹已经存在,新建成功"
[ -d beijing ] && echo "beijing文件夹已经存在,新建成功"
[ -d shanghai ] && echo "shanghai文件夹已经存在,新建成功"rm -rf feng??.txt
# 建一个文件包含当前日期,日期精确到秒
touch sc$(date +%Y%m%d%H%M%S)-{1..10}.txtif useradd zheng;thenecho "123456"|passwd zheng --stdin
elseexit 9 # 设置返回值为9
fiecho "脚本执行完毕"[root@hz shell]# bash create_file.sh
hunan文件夹已经存在,新建成功
beijing文件夹已经存在,新建成功
shanghai文件夹已经存在,新建成功
更改用户 zheng 的密码 。
passwd:所有的身份验证令牌已经成功更新。
脚本执行完毕
[root@hz shell]# echo $?
9
[root@hz shell]# ls /backup # 验证
beijing feng3.txt feng7.txt sch20250706173336-10.txt sch20250706173336-4.txt sch20250706173336-8.txt
feng100.txt feng4.txt feng8.txt sch20250706173336-1.txt sch20250706173336-5.txt sch20250706173336-9.txt
feng1.txt feng5.txt feng9.txt sch20250706173336-2.txt sch20250706173336-6.txt shanghai
feng2.txt feng6.txt hunan sch20250706173336-3.txt sch20250706173336-7.txt
5.2 case多分支
case
变量 in
模式1)
命令1
;;
# 终止一个模式分支
模式2|模式3)
# 多个模式用竖线分隔
命令2
;;
*)
# 默认分支
默认命令
;;
esac
[root@hz shell]# vim case.sh
#!/bin/bash
case $1 in
start)echo "开始执行相关操作"mkdir case_start;;
stop)echo "开始停止操作"mkdir case_stop;;
restart|reload|reboot)echo "开始重启操作"mkdir case_restart;;
*) echo "用法 $0 start|stop|restart|reload|reboot";;
esac
[root@hz shell]# bash case.sh start
开始执行相关操作
[root@hz shell]# bash case.sh stop
开始停止操作
[root@hz shell]# bash case.sh reload
开始重启操作
[root@hz shell]# ls
case_restart case.sh case_start case_stop
[root@hz shell]# bash case.sh 1
用法 case.sh start|stop|restart|reload|reboot
if的多分支实现
[root@hz shell]# vim if3.sh
#!/bin/bash
if [[ $1 == "start" || $1 == "START" ]];thenecho "starting" && mkdir starting
elif[[ $1 == "stop" || $1 == "STOP" ]];thenecho "stoping" && mkdir stoping
elif[[ $1 == "restart" || $1 == "RESTART" ]];thenecho "restart"
elseecho "usage: $0 start|stop|restart"
fi[root@hz shell]# bash if3.sh restart
restart
5.3 for循环
for
变量 in
集合
do
命令
done
[root@hz shell]# vim for.sh
#!/bin/bash
for i in {1..5}
doecho $i
done[root@hz shell]# bash for.sh
1
2
3
4
5
5.4 while循环
while
条件(可以是执行一条命令)
do
命令
done
[root@hz shell]# vim while.sh
i=1
while (( $i < 10 )) # 双圆括号:进行整数数值的比较和运算
do((i++))echo "$i "sleep 3 # 让当前进程暂停执行 3 秒
done
while 死循环
while true
while :
[root@hz shell]# vim while.sh
#!/bin/bash
i=1
while true
do((i++))echo "$i"sleep 3
done#控制循环次数为10次
i=1
#while true
while :
do((i++))echo "$i "sleep 1if (( $i == 10));thenbreakfi
done
有一个成绩文件grade.txt里面记录了很多同学的成绩,具体如下:
[root@hz shell]# vim grade.txt
id name sex chinese English math
1 cali m 80 70 60
2 rose f 90 98 97
3 tom f 70 60 60
4 jack m 99 99 68
编写脚本select_grade.sh 查询出语文成绩大于85的人的名字,性别,English,math,chinese
[root@hz shell]# vim select_grade.sh
#!/bin/bash
#让while循环去读取grade.txt文件里的内容,在读取文件的时候,是一行一行读取的
while read id name sex chinese English math
doif (( $chinese > 85 ));thenecho "$name $sex $English $math $chinese"fi
done < grade.txt # 读取 grade.txt 文件[root@hz shell]# bash select_grade.sh
select_grade.sh:行5: ((: chinese:表达式递归层次越界 (错误符号是 "chinese")
rose f 98 97 90
jack m 99 68 99
算术表达式错误
(( $chinese > 85 )) 中的 $chinese 为非数字,导致 Shell 无法将其解释为有效的数值
1. 赋值为字符串
当 while 循环读取首行时,变量 chinese 的值会被赋值为字符串 “chinese”。此时:
[[ $chinese == “chinese” ]] 条件成立,执行 continue 跳过后续处理,避免将标题行作为数据处理
[root@hz shell]# cat select_grade.sh
#!/bin/bash
while read id name sex chinese English math
doif [[ $chinese == "chinese" ]];thencontinuefiif (( $chinese > 85 ));thenecho "username:$name sex:$sex English:$English math:$math chinese:$chinese"fi
done < grade.txt[root@hz shell]# bash select_grade.sh
username:rose sex:f English:98 math:97 chinese:90
username:jack sex:m English:99 math:68 chinese:99
2. 使用正则表达式
用正则表达式检查chinese变量是否包含任意字母
先排除非数字的干扰行(如标题),再对有效数据进行条件筛选
[root@hz shell]# echo “fjgh”|grep “[a-Z]”
fjgh
[root@hz shell]# echo $?
0
[root@hz shell]# echo “123456”|grep “[a-Z]”
[root@hz shell]# echo $?
1
[a-z]
代表小写a到Z
[A-Z]
代表大写A到Z
[a-Z]
代表所有的小写a到z和大写的A到Z
[0-9]
代表0到9的数字
[root@hz shell]# cat select_grade_2.sh
#!/bin/bashwhile read id name sex chinese English math
doif echo $chinese |grep "[a-Z]" &>/dev/null;thencontinuefiif (( $chinese > 85 ));thenecho "username:$name sex:$sex English:$English math:$math chinese:$chinese"fi
done < grade.txt[root@hz shell]# bash select_grade_2.sh
username:rose sex:f English:98 math:97 chinese:90
username:jack sex:m English:99 math:68 chinese:99
read后面接的变量的个数尽量和grade.txt文件里的字段数(列)一样,如果不一致,最后一个变量会包含后面字段的内容
[root@hz shell]# cat select_grade_3.sh
#!/bin/bash
while read id name sex chinese
do echo "username:$name sex:$sex English:$English math:$math chinese:$chinese"
done < grade.txt[root@hz shell]# bash select_grade_3.sh
username:name sex:sex English: math: chinese:chinese English math
username:cali sex:m English: math: chinese:80 70 60
username:rose sex:f English: math: chinese:90 98 97
username:tom sex:f English: math: chinese:70 60 60
username:jack sex:m English: math: chinese:99 99 68
六、命令替换
优先执行命令,然后将命令执行结果赋值给变量
- varname=
$(命令)
--》推荐 - 反引号 varname=
`命令`
单引号和双引号
单引号 : 任何字符串都只是字符串本身,没有特殊作用 --》所见即所得
双引号: 里面的特殊符号,例如 $ 表示引用变量的值
[root@localhost feng]# city=changsha
[root@localhost feng]# echo “hello,$city”
hello,changsha
[root@localhost feng]# echo ‘hello,$city’
hello,$city
[root@localhost feng]# bigcity=`echo “hello,$city”`
[root@localhost feng]# echo $bigcity
hello,changsha
[root@localhost feng]# bigcity2=$(echo “hello,$city”)
[root@localhost feng]# echo $bigcity2
hello,changsha
七、 函数
function
一个功能用一个函数来实现
模块化 --》复用
1. 函数定义与使用
编写简单的加法函数
[root@hz shell]# vim f1.sh
#!/bin/bash
add() {total=$(( $1 + $2 ))echo "total is $ total"return 0
}add 50 60[root@hz shell]# bash f1.sh
total is 110
[root@hz shell]# echo $?
0
整个脚本的返回值取决于最后一条命令执行的返回值
return是退出函数的时候,给的返回值
exit是退出整个脚本的时候,给的返回值
[root@hz shell]# vim f1.sh
#!/bin/bash
add() {total=$(( $1 + $2 ))echo "total is $total"return 10
}add 50 60
echo "ok"
exit 99
echo "1"[root@hz shell]# bash f1.sh
total is 110
ok
[root@hz shell]# echo $?
99
结合位置变量
[root@hz shell]# cat f2.sh
#!/bin/bash
num1=$1
num2=$2
add() {total=$(( $num1 + $num2 ))echo "total is $total"return 0
}add[root@hz shell]# bash f2.sh 50 60
total is 110
2. 函数嵌套和变量的作用域问题
函数自己也可以调用自己 --》循环的效果
A函数里的变量i,B函数也可以引用的,默认函数里的变量是全局变量,其他函数可以使用,所以注意变量名不要重复
整个脚本文件作为一个函数库文件,里面包含了很多的函数,其他的脚本文件直接导入就可以使用里面的函数
local
声明局部变量,限制变量的作用域仅在当前函数或代码块内,避免污染全局环境
全局变量和局部变量示例
# 定义加减法函数并展示结果
# total1和total2未使用local声明,成为全局变量
[root@hz shell]# vim f2.sh
#!/bin/bash
num1=$1
num2=$2
add() {total1=$(( $num1 + $num2 ))echo "sum total is $total1"return 10
}
sub() {total2=$(( $num1 - $num2 ))echo "sub total is $total2"return 11
}
sc(){echo "求和: $total1 减法: $total2"
}add
sub
sc[root@hz shell]# bash f2.sh 99 88
sum total is 187
sub total is 11
求和: 187 减法: 11# 在 add() 和 sub() 中,total1 和 total2 被声明为 局部变量,
# 其作用域仅限于函数内部,因此 sc() 输出的是未定义的变量(空值)
[root@hz shell]# vim f2.sh
#!/bin/bash
num1=$1
num2=$2
add() {local total1=$(( $num1 + $num2 ))echo "sum total is $total1"return 10
}
sub() {local total2=$(( $num1 - $num2 ))echo "sub total is $total2"return 11
}
sc(){echo "求和: $total1 减法: $total2"
}add
sub
sc[root@hz shell]# bash f2.sh 99 88
sum total is 187
sub total is 11
求和: 减法:
即使通过 source 导入脚本,其他函数(如 sc())仍然无法直接访问这些局部变量
当 add() 和 sub() 执行结束后,其局部变量会被销毁
sc() 调用时,total1 和 total2 已不存在,因此显示为空
[root@hz shell]# vim f3.sh
#!/bin/bash
num1=$1
num2=$2
add() {local total1=$(( $num1 + $num2 ))echo "sum total is $total1"return 10
}
sub() {local total2=$(( $num1 - $num2 ))echo "sub total is $total2"return 11
}
sc(){echo "求和: $total1 减法: $total2"
}[root@hz shell]# vim f4.sh
#!/bin/bash# 导入f3.sh脚本文件,获取里面的函数
source f3.sh
# .f3.shmul() {echo "乘法结果: $((num1 * num2)) "
}
add
sub
sc
mul[root@hz shell]# bash f4.sh 90 80
sum total is 170
sub total is 10
求和: 减法:
乘法结果: 7200
八、数组
是一个集合,里面有很多的东西(数字,字符串)
元素:是一个数组里的一个内容
下标(索引):是数组里的内容的编号
数组的定义
使用括号 ()
包裹元素,元素间用空格分隔
singers=(“zouqiang” “caojie” “zhoujielun” “rose”)
0 1 2 3
[root@rocky ~]# singers=(“zouqiang” “caojie” “zhoujielun” “rose”)
# 通过下标访问元素
[root@rocky ~]# echo ${singers[0]}
zouqiang
# 访问所有元素
[root@rocky shell]# echo ${singers[@]}
zouqiang caojie zhoujielun rose
# 获取数组元素个数
[root@rocky ~]# echo ${#singers[@]}
4
# 获取所有下标
[root@rocky ~]# echo ${!singers[@]}
0 1 2 3
# 删除一个元素,会导致下标不连续
[root@rocky ~]# unset singers[2]
[root@rocky ~]# echo ${!singers[@]}
0 1 3
[root@rocky ~]# echo ${#singers[@]}
3
# 从命令输出创建数组
[root@rocky ~]# name=($(cat /etc/passwd|awk -F: ‘{print $1}’))
[root@rocky ~]# echo ${name[@]}
root bin daemon adm lp sync shutdown halt mail operator games
编写一个点歌程序sing.sh 从歌手名单singers.txt里随机抽取歌手,当所有的歌手都抽取完后,重新开始
歌手文件
[root@rocky shell]# cat singers.txt
tom
jerry
rose
jack
feng
li
zhang
脚本文件
>[root@rocky shell]# cat sing.sh
#!/bin/bash
singers=($(cat singers.txt))
# 随机抽取歌手
while true
doif (( ${#singers[@]} == 0 ));thenecho "所有的歌手都抽取完毕,需要重新开始"exit filucky_num=$(( RANDOM % ${#singers[@]}))echo "请著名歌手 ${singers[$lucky_num]}"unset singers[$lucky_num]singers=($(echo ${singers[@]}))read -p "请输入任意键继续"
done
执行效果
[root@rocky shell]# bash sing.sh
请著名歌手 jerry
请输入任意键继续
请著名歌手 li
请输入任意键继续
请著名歌手 feng
请输入任意键继续
请著名歌手 tom
请输入任意键继续
请著名歌手 jack
请输入任意键继续
请著名歌手 zhang
请输入任意键继续
请著名歌手 rose
请输入任意键继续
所有的歌手都抽取完毕,需要重新开始
用文件来存放已经抽取过的名单
[root@rocky shell]# cat sing2.sh
#!/bin/bash
# 新建一个存放已经唱过歌的歌手的名单文件
>pass.txt
i=1
while :
do pass_lines=$(cat pass.txt|wc -l)total_lines=$(cat singers.txt|wc -l)# 判断pass.txt和singers.txt文件的行数是否一样,来判断歌手是否全部唱完if (( $pass_lines == $total_lines ));thenecho "全部歌手已经唱完,重新开始"exitfi# 随机抽取一个歌手对应的行数lucky_num=$(( $RANDOM % $total_lines + 1))# 歌手的名字singer_name=$(cat singers.txt |head -n $lucky_num |tail -1)if grep $singer_name pass.txt &>/dev/null ;thencontinueelseecho "$i 请著名歌手 $singer_name 演唱歌曲"|tee -a pass.txtfisleep 1((i++))
done
[root@rocky shell]# bash sing2.sh
1 请著名歌手 zhang 演唱歌曲
2 请著名歌手 feng 演唱歌曲
3 请著名歌手 jerry 演唱歌曲
4 请著名歌手 tom 演唱歌曲
5 请著名歌手 jack 演唱歌曲
6 请著名歌手 rose 演唱歌曲
7 请著名歌手 li 演唱歌曲
全部歌手已经唱完,重新开始
总结
Shell 脚本的价值在于将人力从重复劳动中解放出来,通过代码实现:
- 效率提升:减少手动操作,缩短任务执行时间
- 一致性:避免人工误差,确保每次执行结果相同
- 可维护性:将操作步骤文档化,便于团队协作和知识传承
- 扩展性:可与其他工具无缝集成,构建复杂的自动化系统