41.Shell Case选择 While循环
文章目录
- Shell Case选择 While和for循环
- Shell 编程 case 语句
- case 基本概念
- 什么是 case 语句?
- case 基本语法
- 完整语法结构
- 示例
- 常用通配符
- 示例
- 示例1:判断数字
- 示例2:控制sshd服务
- 示例3:管理用户实践
- Shell 编程 while 循环
- while 基本概念
- 什么是 while 循环?
- while 基本语法
- 基本语法结构
- 或者写成一行:
- 示例
- 示例1:定一个小目标
- 示例2:监视sshd服务
- 示例3:猴子吃桃
- Shell 编程 for 循环
- for 基本概念
- 什么是 for 循环?
- for 基本语法
- 基本语法结构
- 一行写法
- 示例
- 示例1:竖向升序打印
- 示例2:竖向降序打印
- 示例3:求和、求乘积
- 示例4:99乘法表
Shell Case选择 While和for循环
Shell 编程 case 语句
case 基本概念
什么是 case 语句?
case 语句是一种多分支选择结构,用于根据变量的值执行不同的代码块。它比多个 if-elif 语句更加简洁和高效。
case 基本语法
完整语法结构
case 变量 in
模式1)命令序列1;;
模式2)命令序列2;;
模式3)命令序列3;;
*)默认命令序列;;
esac
示例
#!/bin/bashfruit="apple"case $fruit inapple)echo "这是苹果";;banana)echo "这是香蕉";;orange)echo "这是橙子";;*)echo "未知水果";;
esac
常用通配符
通配符 | 说明 | 示例 |
---|---|---|
* | 匹配任意字符(包括空字符) | *.txt |
? | 匹配单个任意字符 | file?.txt |
[] | 匹配括号内的任意一个字符 | [abc].txt |
[!] | 不匹配括号内的任意字符 | [!0-9] |
示例
示例1:判断数字
[hxl@server bin 14:33:01]$ vim case1.sh
[hxl@server bin 14:35:42]$ cat case1.sh
#!/bin/bash
read -p "请输入一个1-3之间数字:" num
case $num in
1)echo "您输入的数字是:$num";;
2)echo "您输入的数字是:$num";;
3)echo "您输入的数字是:$num";;
*)echo "请在1-3之间输入一个数字。";;
esac[hxl@server bin 14:35:45]$ bash case1.sh
请输入一个1-3之间数字:1
您输入的数字是:1
[hxl@server bin 14:35:53]$ bash case1.sh
请输入一个1-3之间数字:4
请在1-3之间输入一个数字。
示例2:控制sshd服务
[hxl@server bin 14:50:37]$ vim ssh_ctl_case.sh
[hxl@server bin 14:52:03]$ cat ssh_ctl_case.sh
#!/bin/bash
case $1 in start)systemctl start sshd;;stop)systemctl stop sshd;;restart | reload ) systemctl restart sshd;; status ) systemctl status sshd;; *)echo "Usage: case-ssh start|stop|restart|reload|status";;
esac
[hxl@server bin 14:52:06]$ bash ssh_ctl_case.sh
Usage: case-ssh start|stop|restart|reload|status
[hxl@server bin 14:52:17]$ bash ssh_ctl_case.sh status
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: active (running) since 五 2025-10-10 13:00:52 CST; 1h 51min agoDocs: man:sshd(8)man:sshd_config(5)Main PID: 1054 (sshd)CGroup: /system.slice/sshd.service└─1054 /usr/sbin/sshd -D
脚本优化
#!/bin/bash
case $1 in start | stop | restart | reload | status)systemctl $1 sshd;;*)echo "Usage: case-ssh start|stop|restart|reload|status";;
esac
示例3:管理用户实践
通过传参的方式往 /etc/users 里添加用户,具体要求如下。
-
命令用法为:
Usage: user-mgr [ [-add|-a ] | [ -d|-del ] | [ -s|-search ] ] username
-
传参要求为:
- 参数为-add|-a时,表示添加后面接的用户名。如果有同名的用户, 则不能添加。
- 参数为-del|-d时,表示删除后面接的用户名。如果用户不存在,提示用户不存在。
- 参数为-search|-s时,表示查找后面接的用户名。 如果用户不存在,提示用户不存在。
- 没有用户时应给出明确提示。
-
/etc/users 保存用户清单,格式如下:
username: laoma username: laowang
-
/etc/users 不能被外部其他程序直接删除及修改。
[hxl@server bin 15:20:50]$ vim user-mgr
[hxl@server bin 15:26:04]$ cat user-mgr
#!/bin/bash# run as root[ $UID != 0 ] && echo "Please run as root" && exit 1# create users file
users_info_file=/etc/users
[ -f ${users_info_file} ] || touch ${users_info_file}# provides two args
if [ $# != 2 ];thenecho "Usage: user-mgr [ [ -add|-a ] | [ -del|-d ] | [ -search|-s ] ] username"exit 2
fi# get arg value
action=$1
username=$2# manager user
case $action in-s|-search)if grep -q "username: $username" ${users_info_file};thenecho "$username is exist."elseecho "$username is not exist."fi;;-a|-add)if grep -q "username: $username" ${users_info_file};thenecho "$username is exist."elsechattr -i ${users_info_file}echo "username: $username" >> ${users_info_file}echo "$username has been added."chattr +i ${users_info_file}fi;;-d|-del)if grep -q "username: $username" ${users_info_file};thenchattr -i ${users_info_file}sed -i "/username: $username/d" ${users_info_file}chattr +i ${users_info_file}echo "$username has been deleted."elseecho "$username is not exist."fi;;*)echo "Usage: user-mgr [ [ -add|-a ] | [ -del|-d ] | [ -search|-s ] ] username";;
esac
关键要点:
- 使用
|
分隔多个模式 - 总是包含
*)
默认情况 - 每个模式块以
;;
结束 - 整个 case 以
esac
结束 - 合理使用通配符进行模式匹配
Shell 编程 while 循环
while 基本概念
什么是 while 循环?
while 循环是一种条件循环,只要条件为真就会重复执行循环体内的代码。它是 Shell 编程中最常用的循环结构之一。
while 基本语法
基本语法结构
while [ condition ]
do# 循环体commands
done
或者写成一行:
while [ condition ]; do commands; done
示例
示例1:定一个小目标
[hxl@server bin 15:20:11]$ vim hardwork.sh
[hxl@server bin 15:20:36]$ cat hardwork.sh
#!/bin/bash
money=0
target=10000000
while (( $money < $target ))
doecho -n "I'm working hard ... total: "money=$[ money + 1000000 ]echo $moneysleep 0.5
done
[hxl@server bin 15:20:41]$ bash hardwork.sh
I'm working hard ... total: 1000000
I'm working hard ... total: 2000000
I'm working hard ... total: 3000000
I'm working hard ... total: 4000000
I'm working hard ... total: 5000000
I'm working hard ... total: 6000000
I'm working hard ... total: 7000000
I'm working hard ... total: 8000000
I'm working hard ... total: 9000000
I'm working hard ... total: 10000000
示例2:监视sshd服务
需求:
后台监视sshd服务,一旦发现sshd服务未运行,就start sshd。
每隔3秒检测一次。不允许使用计划任务(cron)。
[hxl@server bin 15:44:31]$ cat monitor_sshd.sh
#!/bin/bashwhile true
dosystemctl is-active sshd &> /dev/nullreturn_count=$?if (( return_count != 0 ));thensystemctl start sshdelse sleep 3fidone
示例3:猴子吃桃
- 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。
- 第二天早上又将第一天剩下的桃子吃掉一半,又多吃了一个。
- 以后每天早上都吃了前一天剩下的一半零一个。
- 到第 10 天早上想再吃时,发现只剩下一个桃子了。
问:一共有多少个桃子?
[hxl@server bin 15:59:08]$ vim peach.sh
[hxl@server bin 16:04:55]$ cat peach.sh
#!/bin/bash# 当天桃子数量,第一天为1
today=1# 前一天桃子数量
lastday=0# 迭代9次
i=1
while (( i <= 9 ))
do# 计算上一天的桃子数量lastday=$[ (today+1)*2 ]# 把上一天的数量当作今天的数量today=${lastday}echo "猴子第$[ 10-i ]天摘得桃子数量是:$today."(( i++ ))
done[hxl@server bin 16:06:36]$ bash peach.sh
猴子第9天摘得桃子数量是:4.
猴子第8天摘得桃子数量是:10.
猴子第7天摘得桃子数量是:22.
猴子第6天摘得桃子数量是:46.
猴子第5天摘得桃子数量是:94.
猴子第4天摘得桃子数量是:190.
猴子第3天摘得桃子数量是:382.
猴子第2天摘得桃子数量是:766.
猴子第1天摘得桃子数量是:1534.
关键要点:
- 确保循环条件最终会变为假,避免无限循环
- 使用
break
提前退出循环 - 使用
continue
跳过本次循环 - 在循环中妥善处理变量和资源
- 注意循环的性能影响
Shell 编程 for 循环
for 基本概念
什么是 for 循环?
for 循环是一种迭代循环,用于遍历列表中的每个元素或执行指定次数的循环。它是 Shell 编程中最灵活和常用的循环结构。
for 基本语法
基本语法结构
for 变量 in 值列表
do# 循环体commands
done
一行写法
for 变量 in 值列表; do commands; done
示例
seq 语法:seq [选项] 第一个数 [增量] 最后一个数(默认从1开始)
seq 5 表示从1打印到5
示例1:竖向升序打印
列表型
[hxl@server bin 16:20:14]$ cat > for1.sh << 'EOF'
> #!/bin/bash
> for i in {1..5}
> do
> echo $i
> done
> EOF
> [hxl@server bin 16:27:34]$ bash for1.sh
> 1
> 2
> 3
> 4
> 5[hxl@server bin 16:28:44]$ vim for2.sh
[hxl@server bin 16:29:29]$ cat for2.sh
#!/bin/bash
for i in $(seq 5)
doecho $i
done
[hxl@server bin 16:29:32]$ bash for2.sh
1
2
3
4
5
c语言型
[hxl@server bin 16:29:40]$ vim for3.sh
[hxl@server bin 16:43:50]$ cat for3.sh
#!/bin/bash
for (( i=1;i<=5;i++ ))
doecho $i
done
while型
[hxl@server bin 16:43:53]$ vim while1.sh
[hxl@server bin 16:44:57]$ cat while1.sh
#!/bin/bash
i=1
while (( i<=5 ))
doecho $i((i++))
done
示例2:竖向降序打印
[hxl@server bin 16:45:00]$ vim for4.sh
[hxl@server bin 16:47:16]$ cat for4.sh
#!/bin/bash
for i in {5..1}
doecho $i
done
[hxl@server bin 16:47:19]$ bash for4.sh
5
4
3
2
1[hxl@server bin 16:47:27]$ vim for5.sh
[hxl@server bin 16:48:26]$ cat for5.sh
#!/bin/bash
for i in $(seq 5 -1 1)
doecho $i
done
示例3:求和、求乘积
seq -s 表示指定分隔符
求和
[hxl@server bin 16:48:49]$ vim for6.sh
[hxl@server bin 16:50:12]$ cat for6.sh
#!/bin/bash
sum=0
for i in {1..10}
dosum=$[ sum + i ]
done
echo $(seq -s '+' 10)=$sum
[hxl@server bin 16:50:14]$ bash for6.sh
1+2+3+4+5+6+7+8+9+10=55
求积
[hxl@server bin 16:54:56]$ vim for7.sh
[hxl@server bin 16:57:06]$ cat for7.sh
#!/bin/bash
sum=1
for i in {1..10}
dosum=$[ sum * i ]
done
echo $(seq -s '*' 10)=$sum
[hxl@server bin 16:57:10]$ bash for7.sh
1*2*3*4*5*6*7*8*9*10=3628800
示例4:99乘法表
[hxl@server bin 16:58:26]$ vim 99.sh
[hxl@server bin 17:00:47]$ cat 99.sh
#!/bin/bash
for (( i=1;i<=9;i++ ))
dofor (( j=1;j<=i;j++ ))doecho -en "$i*$j=$[ i*j ]\t"doneecho
done[hxl@server bin 17:00:50]$ bash 99.sh
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
选择指南:
- 遍历列表:使用
for item in list
- 固定次数:使用
for ((i=0; i<N; i++))
- 文件处理:使用
for file in pattern
- 复杂逻辑:结合
while
和if
语句