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 条件测试

  1. 文件测试

[ -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

  1. 数值比较

推荐使用双圆括号

[ 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

  1. 字符串比较

[ "$a" = "$b" ] 相等
[ "$a" != "$b" ] 不相等
[ -n "$a" ][ "$a" ] 一样 判断字符串$a长度是否大于0
[ -z $a ] 判断$a 的长度是否为0
[[ "$a" == *"redhat"* ]] 判断在$a中是否含有redhat字符串

  1. 逻辑组合

&&(与) 、||(或)、!(非)

命令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

六、命令替换

优先执行命令,然后将命令执行结果赋值给变量

  1. varname=$(命令) --》推荐
  2. 反引号 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 脚本的价值在于将人力从重复劳动中解放出来,通过代码实现:

  • 效率提升:减少手动操作,缩短任务执行时间
  • 一致性:避免人工误差,确保每次执行结果相同
  • 可维护性:将操作步骤文档化,便于团队协作和知识传承
  • 扩展性:可与其他工具无缝集成,构建复杂的自动化系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88848.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88848.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88848.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【嵌入式】51单片机学习笔记-Keil5软件安装教程

00. 目录 文章目录00. 目录01. Keil C51概述02. Keil C51下载03. Keil C51安装04. Keil C51注册05. 附录01. Keil C51概述 Keil C51 是德国Keil公司&#xff08;现被ARM收购&#xff09;开发的嵌入式开发工具&#xff0c;专注于8051单片机的C语言和汇编开发。它是μVision IDE…

ai之 ubuntu本地安装mineru2.1.0

MinerU 目录 一、更新内容概述写在前面的话:总体来看,2.0版本升级为全新的 VLM 解析模式,更优于以前的基础解析方式。二、MinerU 安装部署下面使用源码来进行环境安装。注意:当前状态说明推荐解决方案如果是下载插件慢可以 指定阿里源三、MinerU 使用1. 在线体验2. 命令行使…

华为昇腾NPU与NVIDIA CUDA生态兼容层开发实录:手写算子自动转换工具链(AST级代码迁移方案)

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生专属优惠。 当国产AI芯片崛起遭遇生态壁垒&#xff0c;如何实现CUDA算子到昇腾平台的无损迁移成为关键挑…

GraphRAG Docker化部署,接入本地Ollama完整技术指南:从零基础到生产部署的系统性知识体系

相关推荐&#xff1a;Umi-OCR 的 Docker安装&#xff08;win制作镜像&#xff0c;Linux&#xff08;Ubuntu Server 22.04&#xff09;离线部署&#xff09; 一、技术背景与发展脉络 1.1 RAG技术演进历程分析 检索增强生成&#xff08;RAG&#xff09;技术的发展经历了三个重要…

Android 系统默认Launcher3 菜单模式双层改成单层-3

Android 系统默认自带Launcher3 菜单都为双层模式 各手机大厂的Launcher的菜单模式都为单层 如何将launcher3的菜单模式改为单层模式 mOverviewPanel = (ViewGroup) findViewById(R.id.overview_panel); mWidgetsButton = findViewById(R.id.widget_butto…

基于k8s环境下pulsar高可用测试和扩缩容(上)

#作者&#xff1a;任少近 文章目录Pulsar高可用测试1. 测试目的2.当前集群环境说明3. 模拟故障场景4.功能验证5.结论Pulsar高可用测试 1. 测试目的 本次测试旨在验证 Apache Pulsar 在某个 Broker 节点宕机&#xff08;down&#xff09;的情况下&#xff0c;是否仍能正常提供…

JAVA JVM垃圾收集

JVM 垃圾收集是 Java 自动内存管理的核心&#xff0c;本文通过围绕 “哪些是垃圾、何时回收、怎么回收、用啥回收器、内存咋分配” 等展开一、判断哪些是垃圾引用计数法&#xff1a;给对象分配引用计数器&#xff0c;有引用时计数加 1&#xff0c;引用失效减 1 &#xff0c;计数…

UniHttp生命周期钩子与公共参数实战:打造智能天气接口客户端

> 通过灵活的生命周期钩子,我们让HTTP请求从机械操作进化为智能对话 在现代应用开发中,高效处理HTTP请求是核心能力。本文将深入探索UniHttp框架中强大的**HttpApiProcessor生命周期钩子**,并演示如何利用其**公共参数填充机制**优雅地处理第三方接口。我们将以百度天…

C++高级编程,类模版成员函数类外实现

#include <iostream> #include <string>//类模版成员函数类外实现 template<class T1,class T2> class Person {//Person构造函数 public:Person(T1 name,T2 age);// {// this->m_Namename;// this->m_Ageage;// }//Person的成员函数void show…

[Linux入门 ] RAID存储技术概述

一.数据存储架构 1️⃣存储系统 2️⃣主机系统 3️⃣互连部件 4️⃣存储设备与磁盘阵列 二.数据存储技术 1️⃣数据冗余技术 2️⃣RAID 0 3️⃣RAID 1 4️⃣RAID 2 5️⃣RAID 3 6️⃣RAID 4 三.基于硬件的RAID磁盘阵列 1️⃣阵列卡(RAID控制器) 2️⃣阵列卡种类 …

AI绘画生成章邯全身像提示词

融合了历史元素和视觉表现力&#xff0c;力求生成符合秦末名将章邯身份的全身像。 核心提示词结构&#xff1a; [主体描述]&#xff0c;[服装/盔甲细节]&#xff0c;[姿态/神情]&#xff0c;[武器]&#xff0c;[背景/氛围]&#xff0c;[风格/质量]&#xff0c;[参数] 选项一&…

iOS高级开发工程师面试——关于优化

iOS高级开发工程师面试——关于优化 一、TableView 有什么好的性能优化方案?二、界面卡顿和检测你都是怎么处理?三、谈谈你对离屏渲染的理解?四、如何降低APP包的大小?五、日常如何检查内存泄露?六、APP启动时间应从哪些方面优化?一、TableView 有什么好的性能优化方案?…

线性基学习笔记

我们称一个线性空间 V V V 的一个极大线性无关集为这个线性空间的线性基,简称基。 异或线性基 在异或空间下,我们定义如下内容。 异或和 设 S S

ESP-Timer入门(基于ESP-IDF-5.4)

主要参考资料&#xff1a; ESP 定时器&#xff08;高分辨率定时器&#xff09;: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/system/esp_timer.html 目录ESP-Timer与FreeRTOS TimerAPI 使用1.创建定时器2.启动定时器3.管理定时器4.时间管…

014_批处理与大规模任务

批处理与大规模任务 目录 批处理概述核心优势技术规格API使用管理和监控应用场景最佳实践 批处理概述 什么是批处理 批处理&#xff08;Batch Processing&#xff09;是一种异步处理大量Claude API请求的方法&#xff0c;允许您一次性提交多个消息请求&#xff0c;系统将在…

Python淘宝拍立淘按图搜索API接口,json数据示例参考

淘宝拍立淘按图搜索API接口示例淘宝的拍立淘(图片搜索)功能通常是通过淘宝开放平台提供的API实现的。以下是一个模拟的JSON数据示例和接口调用参考&#xff1a;模拟API请求示例import requestsimport base64# 示例图片路径image_path "example.jpg"# 读取图片并编码…

静默的田野革命—人工智能重构农业生态的技术风暴与文明悖论

一、饥饿困局的数字突围当全球粮食损失率高达30%&#xff08;约13亿吨&#xff09;与8亿人营养不良并存&#xff0c;当农药滥用导致传粉昆虫种群崩溃与地下水资源枯竭&#xff0c;传统农业的生态死结日益收紧。这场危机的核心是生物复杂性对工业化农业的报复&#xff1a;小麦基…

【大模型推理论文阅读】 Thinking Tokens are Information Peaks in LLM Reasoning

Demystifying Reasoning Dynamics with Mutual Information&#xff1a;Thinking Tokens are Information Peaks in LLM Reasoning 摘要 大语言推理模型&#xff08;LRM&#xff09;在复杂问题解决方面展现出了令人瞩目的能力&#xff0c;但其内部推理机制仍未得到充分理解。…

【TCP/IP】14. 远程登录协议

14. 远程登录协议14. 远程登录协议14.1 基本概念14.2 Telnet 命令14.3 Telnet 选项及协商14.4 Telnet 子选项协商14.5 Telnet 操作模式本章要点14. 远程登录协议 14.1 基本概念 Telnet 协议是 TCP/IP 协议族的重要成员&#xff0c;核心功能是实现本地计算机对远程主机的终端仿…

Flink1.20.1集成Paimon遇到的问题

flinkcdc mysql 到paimon 1&#xff1a;Caused by: java.lang.ClassNotFoundException: org.apache.kafka.connect.data.Schema 可以参考这个文章 明确指出了flink-connector-mysql-cdc-3.4.0.jar存在这个包&#xff0c;但是flink-sql-connector-mysql-cdc-3.4.0.jar中没有这个…