当前位置: 首页 > news >正文

Linux shell脚本条件循环

while 循环和 until 循环的应用实践

循环语句命令常用于重复执行一条指令或一组指令,直到条件不再满足时停止,Shell脚本语言的循环语句常见的有while、until、for及select循环语句。

while 循环语句主要用来重复执行一组命令或语句,在企业实际应用中,常用于守护进程或持续运行的程序,除此以外,大多数循环都会用后文即将讲解的for循环语句。

1 当型和直到型循环语法

1.1 while 循环语句

while 循环语句的基本语法为:

while <条件表达式>
do指令...
done

提示:注意代码缩进。

while 循环语句会对紧跟在while命令后的条件表达式进行判断:

  • 如果该条件表达式成立,则执行while 循环体里的命令或语句(即语法中do和done之间的指令),每一次执行到done时就会重新判断while条件表达式是否成立,直到条件表达式不成立时才会跳出while 循环体。
  • 如果一开始条件表达式就不成立,那么程序就不会进入循环体(即语法中do和done之间的部分)中执行命令了。

为了便于大家记忆,下面是某女生写的while条件语句的中文形象描述:

# 如果男朋友努力工作,则继续相处
while 男朋友努力工作
do继续相处
done

while 循环执行流程对应的逻辑图如下:

在这里插入图片描述

1.2 until 循环语句

until 循环语句的语法为:

until <条件表达式>
do指令...
done

until 循环语句的用法与while 循环语句的用法类似,区别是until会在条件表达式不成立时,进入循环执行指令;条件表达式成立时,终止循环。

为了便于大家记忆,下面是某女生写的until条件语句的中文形象描述:

#如果男朋友不努力工作,就不继续相处
until 男朋友不努力工作
do继续相处 
done

until 循环执行流程对应的逻辑图如下:

在这里插入图片描述

2 当型和直到型循环的基本范例

示例1: 竖向打印54321

while格式:

#!/bin/bash
i=5
while ((i>0))
doecho $i((i--))
done

until格式:

#!/bin/bash
i=5
until ((i==0))
doecho $i((i--))
done

示例2: 计算1+2+3+…+99+100的和

#!/bin/bash
i=1
sum=0
while ((i<=100))
do((sum+=i))# let sum=sum+i((i++))# let i++
done
echo "1+2+3+...+99+100=$sum"

示例3: 计算5的阶乘

#!/bin/bash
i=1
sum=1
while ((i<=5))
do((sum*=i))((i++))
done
echo "5的阶乘为:$sum"

示例4: 猴子吃桃。

  • 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。
  • 第二天早上又将第一天剩下的桃子吃掉一半,又多吃了一个。
  • 以后每天早上都吃了前一天剩下的一半零一个。
  • 到第 10 天早上想再吃时,发现只剩下一个桃子了。

问:一共有多少个桃子?

解题方法1: while 循环9次

#!/bin/bash
# 当天桃子数量,第一天为1
today=1
# 前一天桃子数量
lastday=0
# 只需要迭代9次
i=1
while ((i<=9))
do# 计算上一天桃子数量lastday=$[(today+1)*2]# 把上一天的数量当作今天的数量today=${lastday}((i++))
done
echo "猴子第一天摘的桃子数量是:$today。"

解题方法2: 函数递归调用

#!/bin/bash
function sum (){if [[ $1 = 1 ]];thenecho $1elseecho $[ ($(sum $[$1 -1]) + 1)*2 ]fi
}
echo "猴子第一天摘的桃子数量是:$(sum 10)。"

示例5: 系统随机产生一个50以内数字,猜出该数字,并记录猜测次数。

#!/bin/bash
# 生成随机数字,并保存到文件/tmp/number
random_num=$[ RANDOM%50+1 ]
echo "${random_num}" >> /tmp/number# 记录猜测次数
i=0
while true
doread -p "猜一猜系统产生的50以内随机数是:" numif ((num>=1 && num<=50));then((i++))if [ $num -eq ${random_num} ];thenecho "恭喜你,第$i次猜对了!"# 清理临时文件rm -f /tmp/numberexitelseecho -n "第$i次猜测,加油。"[ $num -gt ${random_num} ] && echo "太大了,往小猜。" || echo "太小了,往大猜。"fielseecho "请输入一个介于1-50之间的数字。"fi 
done

在实际工作中,一般会通过客户端SSH连接服务器,因此可能就会有在脚本或命令执行期间不能中断的需求,若中断,则会前功尽弃,更要命的是会破坏系统数据。

下面是防止脚本执行中断的几个可行方法:

  1. 使用sh /server/scripts/while_01.sh & 命令,即使用 & 在后台运行脚本。

  2. 使用nohup /server/scripts/uptime.sh &命令,即使用 nohup 加&在后台运行脚本。

  3. 利用 screen 保持会话,然后再执行命令或脚本,即使用 screen 保持当前会话状态。

3 让 Shell 脚本在后台运行的知识

脚本运行的相关用法和说明:

  • sh whilel.sh &,把脚本whilel.sh放到后台执行(在后台运行脚本时常用的方法)。
  • ctl+c,停止执行当前脚本或任务。
  • ctl+z,暂停执行当前脚本或任务。
  • bg,把当前脚本或任务放到后台执行。bg可以理解为background。
  • fg,把当前脚本或任务放到前台执行,如果有多个任务,可以使用fg加任务编号调出对应的脚本任务,如fg 2,调出第二个脚本任务。fg可以理解为frontground。
  • jobs,查看当前执行的脚本或任务。
  • kill,关闭执行的脚本任务,即以“kill %任务编号”的形式关闭脚本。任务编号,可以通过jobs命令获得。

示例1: 让所有 CPU 满负荷工作

#!/bin/bash
cpu_count=$(lscpu|grep '^CPU(s)'|awk '{print $2}')
i=1
while ((i<=${cpu_count}))
do{while :do((1+1))done} &((i++))
done

注意:

  • { comand1;command2;command3; …; } &,将多个命令放到后台运行
  • {} 内部两侧有空格。
  • 最后一个命令后有分号。
并发控制

示例1: 消耗完所有CPU

[wsh@test ~ ✔]$ vim cpu_load 
#!/bin/bash
while true
do((1+1))
done[wsh@test ~ ✔]$ vim multi_cpu_load
#!/bin/bash
cpu_count=$(lscpu | awk '/^CPU\(s\):/ { print $2}')
i=1
while [ $i -le 2 ]
dobash /home/wsh/cpu_load &((i++))
done

示例2: 控制并发数量不能超过CPU数量

[wsh@test ~ ✔]$ vim cpu_load
#!/bin/bash
while true
do((1+1))
done &# 只允许改进程运行10s
pid=$!
sleep 10 && kill -9 $pid[wsh@test ~ ✔]$ vim multi_cpu_load
#!/bin/bash
cpu_count=$(lscpu | awk '/^CPU\(s\):/ { print $2}')
while true
dobash /home/wsh/cpu_load &# 控制并发数量不能大于cpu数量  while truedojobs=$(jobs -l |wc -l)if [ $jobs -ge $cpu_count ];then# 如果并发数大于cpu数量,则sleep 3s后继续检测sleep 3else# 如果并发数小于cpu数量,则退出当前while 循环的并发检测breakfidone
done
wait 指令

等后台任务运行完成。

#!/bin/bash
> /tmp/sleep
i=1
while [ $i -le 10 ]
do( sleep $i && echo sleep $i >> /tmp/sleep )&((i++))
done
# 等待前面后台任务运行完成后再运行wait后指令
wait
cat /tmp/sleep

4 企业生产实战:while 循环语句实践

示例1: 每隔2秒输出一次系统负载(负载是系统性能的基础重要指标)情况。

[wsh@test ~ ✔]$ cat while1.sh 
#!/bin/bash
while true
douptimesleep 2
done[wsh@test ~ ✔]$ bash while1.sh20:38:57 up  5:06,  2 users,  load average: 0.00, 0.01, 0.0520:38:59 up  5:06,  2 users,  load average: 0.00, 0.01, 0.0520:39:01 up  5:06,  2 users,  load average: 0.00, 0.01, 0.0520:39:03 up  5:06,  2 users,  load average: 0.00, 0.01, 0.05
^C# 按 ctrl+c 停止运行[wsh@test ~ ✔]$ cat while2.sh 
#!/bin/bash
while true
douptime >> /tmp/loadaverage.logsleep 2
done
# 放到后台运行
[wsh@test ~ ✔]$ bash while2.sh &
[wsh@test ~ ✔]$ tail -f while2.sh

示例2: 后台检测sshd服务,如果未运行,则重启sshd服务。

while格式:

#!/bin/bash
while true
do systemctl is-active sshd.service &>/dev/nullif [ $? -ne 0 ];then systemctl restart sshd.service  &>/dev/nullfisleep 5
done

until格式:

#!/bin/bash
until false
do systemctl is-active sshd.service &>/dev/nullif [ $? -ne 0 ];then systemctl restart sshd.service  &>/dev/nullfisleep 5
done

示例3: 使用while守护进程的方式监控网站,每隔3秒确定一次网站是否正常。

[wsh@test scripts ✔]$ cat check_url.sh 
#!/bin/bashif [ $# -ne 1 ];thenecho "Usage: $0 url"exit 1
fiurl="$1"while true
doif curl -o /dev/null -s --connect-timeout 5 $url;thenecho $url is ok.elseecho $url is error.fisleep 3
done

执行结果

[wsh@test scripts ✔]$ bash check_url.sh 
Usage: check_url.sh url[wsh@test scripts ✔]$ bash check_url.sh www.baidu.com
www.baidu.com is ok.
www.baidu.com is ok.
^C[wsh@test scripts ✔]$ bash check_url.sh www.baidu.co
www.baidu.co is error.
www.baidu.co is error.
^C

示例4: 手机发信息平台:

  • 每发一次短信(输出当前余额)花费1角5分钱
  • 当余额低于1角5分钱时就不能再发短信了,提示“余额不足,请充值”
  • 用户充值后可以继续发短信
#!/bin/bash# 默认金额
money=0.5# 保存消息的文件
msg_file=/tmp/message
# 清空消息文件
> $msg_file# 手机操作菜单
function print_menu () {cat << EOF
1. 查询余额
2. 发送消息
3. 充值
4. 退出
EOF
}# 检查数字函数
function check_digit () {expr $1 + 1 &> /dev/null && return 0 || return 1
}# 显示余额函数
function check_money_all () {echo "余额为:$money。"
}# 检查余额是否充足
function check_money () {new_money=$(echo "$money*100"|bc|cut -d . -f1)if [ ${new_money} -lt 15 ];thenecho "余额不足,请充值。"# 余额不足,返回值为1return 1else# 余额充足,返回值为0return 0fi
}# 充值函数
function chongzhi () {read -p "充值金额(单位:元):" chongzhi_moneywhile truedocheck_digit $chongzhi_moneyif [ $? -eq 0 ] && [ ${chongzhi_money} -ge 1 ];thenmoney=$( echo "($money+${chongzhi_money})"|bc)echo "当前余额为:$money"return 0elseread -p "重新输入充值金额:" chongzhi_money fidone
}# 发送消息函数
function send_msg () {# 检查余额是否充足check_money# 返回值与0比较,判定余额是否充足if [ $? -eq 0 ];thenread -p "msg: " messageecho "$message" >> ${msg_file}# bc计算器计算的结果,如果值小于1,则前面的0省略new_money=$(echo "scale=2;($money*100-15)" | bc |cut -d. -f1 )if [ ${new_money} -ge 100 ];thenmoney=$(echo "scale=2;${new_money}/100" | bc )elsemoney=0$(echo "scale=2;${new_money}/100" | bc )fiecho "当前余额为:$money"fi
}# 主程序
while true
doprint_menuechoread -p "请输入你的选择:" choiceclearcase  $choice in1)check_money_all;;2)send_msg;;3)chongzhi;;4)exit;;*)echo "只能从1、2、3、4中选择。" ;;esacecho
done

5 while 循环按行读文件的方式总结

示例:读取/etc/hosts内容

[wsh@test scripts ✔]$ cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.1.8.88 wsh-shell
  • 方式1:采用exec读取文件,然后进入while 循环处理。
#!/bin/bash
exec < /etc/hosts
while read line
doecho $line
done
  • 方式2:使用cat读取文件内容,然后通过管道进入while 循环处理。
#!/bin/bash
cat /etc/hosts | while read line
doecho $line
done
  • 方式3:在while 循环结尾done处通过输入重定向指定读取的文件。
#!/bin/bash
while read line
doecho $line
done < /etc/hosts
  • 方式4:定义shell分隔符为换行符
#!/bin/bash
IFS=$'\n'
for line in $(cat /etc/hosts)
doecho $line
done

6 while 循环和 until 循环小结

  1. while 循环结构及相关语句综合实践小结
    • while 循环的特长是执行守护进程,以及实现我们希望循环持续执行不退出的应用,适合用于频率小于1分钟的循环处理,其他的while 循环几乎都可以被后面即将要讲到的for循环及定时任务crond功能所替代。
    • case语句可以用if语句来替换,而在系统启动脚本时传入少量固定规则字符串的情况下,多用case语句,其他普通判断多用if语句。
    • 一句话场景下,if语句、for语句最常用,其次是while(守护进程)、case(服务启动脚本)。
  2. Shell脚本中各个语句的使用场景
    • 条件表达式,用于简短的条件判断及输出(文件是否存在,字符串是否为空等)
    • if取值判断,多用于不同值数量较少的情况。
    • for最常用于正常的循环处理中while多用于守护进程、无限循环(要加sleep和usleep控制频率)场景。
    • case多用于服务启动脚本中,打印菜单可用select语句,不过很少见,一般用cat的here文档方法来替代。
    • 函数的作用主要是使编码逻辑清晰,减少重复语句开发。

for 和 select 循环语句的应用实践

for循环语句和while循环语句类似,但for循环语句主要用于执行次数有限的循环,而不是用于守护进程及无限循环。for循环语句常见的语法有两种,下面将在不同的语法中对for循环语句进行详尽的讲解。

1 for 循环语法结构

1.1 变量取值型

第一种for循环语句语法结构如下:

for 变量名 in 变量取值列表
do指令...
done

在此结构中“in 变量取值列表”可以省略,省略时相当于in "$@",也就是使用 for i 就相当于使用for i in "$@"

这种for循环语句执行过程如下:

  1. for关键字后面会有一个“变量名”,变量名依次获取in关键字后面的变量取值列表内容(以空格分隔)。
  2. 每次仅取一个,然后进入循环(do和done之间的部分)执行循环内的所有指令,当执行到done时结束本次循环。
  3. 之后,“变量名”再继续获取变量列表里的下一个变量值,继续执行循环内的所有指令,当执行到done时结束返回。
  4. 以此类推,直到取完变量列表里的最后一个值并进入循环执行到done结束为止。
1.2 C 语言型

第二种for循环语句称为C 语言型for循环,语法结构如下:

for ((expl;exp2;exp3))
do指令...
done

此种循环语句和while循环语句类似,但语法结构比while循环更规范、工整。

这种for循环语句说明如下:

  1. for关键字后的双括号内是三个表达式:

    • 第一个是变量初始化(例如:i=0)

    • 第二个为变量的范围(例如:i<100)

    • 第三个为变量自增或自减(例如:i++)。

  2. 当第一个表达式的初始值符合第二个变量的范围时,就进入循环执行;条件不满足时就退出循环。

for循环结构执行流程对应的逻辑图如下:

在这里插入图片描述

2 for 循环语句的基础实践

示例1:竖向升序打印
# 列表型
[wsh@test ~ ✔]$ vim for1.sh
#!/bin/bash
for i in {1..5}
doecho $i
done
[wsh@test ~ ✔]$ bash for1.sh 
1
2
3
4
5[wsh@test ~ ✔]$ vim for2.sh
#!/bin/bash
for i in $(seq 5)
doecho $i
done# c语言型
[wsh@test ~ ✔]$ vim for3.sh
#!/bin/bash
for ((i=1;i<=5;i++))
doecho $i
done# while型
[wsh@test ~ ✔]$ vim while1.sh
#!/bin/bash
i=1
while ((i<=5)) 
doecho $i((i++))
done
示例2:竖向降序打印
[wsh@test ~ ✔]$ vim for4.sh 
#!/bin/bash
for i in {5..1}
doecho $i
done
[wsh@test ~ ✔]$ bash for4.sh 
5
4
3
2
1[wsh@test ~ ✔]$ vim for5.sh
#!/bin/bash
for i in $(seq 5 -1 1)
doecho $i
done
示例3:求和、求乘积
#!/bin/bash
sum=0
for i in {1..10}
dosum=$[ sum + i ]
done
echo $(seq -s '+' 10)=$sum
#!/bin/bash
sum=1
for i in {1..10}
do((sum*=i))
done
echo $(seq -s '*' 10)=$sum
示例4:求水鲜花数

水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身。

#!/bin/bash
for num in {100..999}
don1=$[num/100]n2=$[num%100/10]n3=$[num%10]if [ $[ n1**3 + n2**3 + n3**3 ] -eq $num ];thenecho $n1^3 + $n2^3 + $n3^3 = $n1$n2$n3fi
done
示例5:九九乘法表
#!/bin/bash
for num1 in {1..9}
dofor ((num2=1;num2<=num1;num2++))doecho -en "$num2*$num1=$[ num2 * num1 ]\t"doneecho
done

3 for 循环语句的企业级案例

示例1: 批量修改文件扩展名(把txt改成jpg)

[wsh@test ~ ✔]$ touch file-{1..3}.txt
[wsh@test ~ ✔]$ ls file-{1..3}.txt
file-1.txt  file-2.txt  file-3.txt# 获取新文件名方法
[wsh@test ~ ✔]$ echo file-3.txt|sed 's/\.txt$/.jpg/'
file-3.jpg
[wsh@test ~ ✔]$ echo $(echo file-3.txt|cut -d. -f1).jpg
file-3.jpg
[wsh@test ~ ✔]$ echo $(echo file-3.txt|awk -F. '{print $1}').jpg # 使用sed
[wsh@test ~ ✔]$ vim for6.sh
#!/bin/bash
for file in $(ls *.txt)
donew_name=$(echo $file|sed 's/.txt$/.jpg/')mv $file ${new_name}
done[wsh@test ~ ✔]$ bash for6.sh 
[wsh@test ~ ✔]$ ls file*
file-1.jpg  file-2.jpg  file-3.jpg# 还可以直接使用rename命令
[wsh@test ~ ✔]$ rename ".jpg" ".txt" *jpg
[wsh@test ~ ✔]$ ls *txt
file-1.txt  file-2.txt  file-3.txt# rename还可用于删除文件名中特定字符串
[wsh@test ~ ✔]$ rename "file-" "" *txt
[wsh@test ~ ✔]$ ls *txt
1.txt  2.txt  3.txt  

示例2: 批量设置服务开启启动

#!/bin/bash
for service in crond atd chronyd 
dosystemctl enable $service
done

示例3: 批量重启多个主机sshd服务

#!/bin/bash
for host in server{1..10}
dossh root@$host systemctl restart sshd
done

示例4: 批量备份文件

#!/bin/bash
for file in host*
docp $file /backup/${file}.bak;
done

4 for 循环语句的企业高级实战案例

# 准备mariadb数据库
[wsh@test scripts ✔]$ sudo yum install -y mariadb-server
[wsh@test scripts ✔]$ sudo systemctl start mariadb

示例1: 实现 MySQL库备份的脚本

创建数据库脚本

[wsh@test scripts ✔]$ vim create_dbs.sh
#!/bin/bash
MYSQL_CMD='mysql -uroot -e '
for db in web1 web2
do${MYSQL_CMD} "create database $db;"
done

执行效果

[wsh@test scripts ✔]$ bash create_dbs.sh
[wsh@test scripts ✔]$ mysql -uroot -e 'show databases;'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| web1               |
| web2               |
+--------------------+

备份数据库脚本

[wsh@test scripts ✔]$ vim dump_dbs.sh
#!/bin/bash
MYSQL_CMD='mysqldump -uroot '
for db in web1 web2
do${MYSQL_CMD} $db > $db.sql;
done

执行效果

[wsh@test scripts ✔]$ bash dump_dbs.sh
[wsh@test scripts ✔]$ ls *sql
web1.sql  web2.sql

示例2: 实现 MySQL分库分表备份的脚本

创建表脚本

[wsh@test scripts ✔]$ vim create_tables.sh
#!/bin/bash
MYSQL_CMD='mysql -uroot $db -e '
for db in web1 web2
do${MYSQL_CMD} "create table test(id int,name varchar(16));insert into test values(1,'testdata')";
done

执行结果

[wsh@test scripts ✔]$ bash create_tables.sh
[wsh@test scripts ✔]$ mysql -uroot -e 'use web1;show tables; select * from test;'
+----------------+
| Tables_in_web1 |
+----------------+
| test           |
+----------------+
+------+----------+
| id   | name     |
+------+----------+
|    1 | testdata |
+------+----------+

备份表脚本

[wsh@test scripts ✔]$ vim dump_tables.sh
#!/bin/bash
MYSQL_CMD='mysqldump -uroot $db'
for db in web1 web2
do${MYSQL_CMD} > ${db}_test.sql;
done

执行效果

[wsh@test scripts ✔]$ bash dump_tables.sh
[wsh@test scripts ✔]$ ls *test.sql
web1_test.sql  web2_test.sql

5 Linux 系统产生随机数的6种方法

方法1: 通过系统环境变量(RANDOM)实现

RANDOM的随机数范围为0~32767,因此加密性不是很好,可以通过在输出的随机数前后增加自定义字符串的方式解决,最后再一起执行md5sUm操作并截取结果的后n位,这样一来,就无法根据随机数范围0~32767来猜出具体结果了。

[wsh@test ~ ✘]$ echo "wsh$RANDOM"|md5sum |cut -c 1-8
d3a8a340

方法2: 通过openssl产生随机数,结果中包涵字母大小写和数字更加安全。

[wsh@test ~ ✔]$ openssl rand -base64 8
Szp2fJ/C7tk=
[wsh@test ~ ✔]$ openssl rand -base64 20
pIELp8BUyTtRIE3v/GNrAijQBLU=

方法3: 通过date命令获得随机数,%N输出纳秒(nanoseconds)。

[wsh@test ~ ✔]$ date +%s%N
1756039707120616853
[wsh@test ~ ✔]$ date +%s%N
1756039710419740788

方法4: 通过设备/dev/urandom或/dev/random和md5sum生成随机数。

这两个设备存储着系统当前运行的环境的实时数据。它可以看作是系统某个时候,唯一值数据,因此可以用作随机数元数据。我们可以通过文件读取方式,读得里面数据。

  • /dev/urandom,返回指定请求数量的随机数,如果请求的数量非常庞大的话,返回的随机数可能是伪随机数,随机数质量稍差些。即使如此,它们对大多数应用来说已经足够了。

  • /dev/urandom,也是返回指定请求数量的随机数,但是它产生的随机数质量很高, 是属于真随机数, 主要用于需要高质量的随机数的地方,比如:生成加密密钥等。

    为了保证随机数的质量,/dev/random只能返回熵池当前最大可用的随机二进制位,当请求超过这个值,就会阻塞,直到熵池中有足够的随机二进制位。

[wsh@test ~ ✔]$ head /dev/urandom |md5sum 
e0a43d0833d3c8431d45b01429734d33  -
[wsh@test ~ ✔]$ head /dev/urandom |md5sum 
f3b8a146781ea92335039464304d5166  -

方法5: 通过UUID生成随机数。

UUID码全称是通用唯一识别码(UniversallyUniqueIdentifier,UUID),它是一个软件建构的标准,亦为自由软件基金会(OpenSoftwareFoundation,OSF)的组织在分布式计算环境(DistributedComputingEnvironment,DCE)领域的一部分。

UUID的目的是让分布式系统中的所有元素都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其他人发生冲突的UUID。在这样的情况下,就不需要考虑数据库创建时的名称重复问题了。它会让网络中任何一台计算机所生成的UUID码都是互联网整个服务器网络中唯一的编码。它的原信息会加人硬件、时间、机器当前运行信息等。

[wsh@test ~ ✔]$ cat /proc/sys/kernel/random/uuid
7323c4ed-8256-45bd-a8f7-8e36e1e03a74
[wsh@test ~ ✔]$ uuidgen 
21258f54-61e2-46af-9abf-a4fbb34bbcd5

方法6: 使用expect附带的mkpasswd命令生成随机数。

[wsh@test ~ ✔]$ mkpasswd -l 20 -d 4 -c 4 -C 4 -s 4
0lyl!7aLnqU-;83[WQlk

选项说明:

  • -l,控制密码长度。
  • -d,控制数字字母最小数量。
  • -c,控制小写字母最小数量。
  • -C,控制大写字母最小数量。
  • -s,控制特殊符号最小数量。

方法7: 使用mktemp命令和sha1sum生成随机数。

[wsh@test ~ ✔]$ mktemp -u 
/tmp/tmp.3XfWcblZDc
[wsh@test ~ ✔]$ mktemp -u |sha1sum 
740fdd67d699071126c52daa1a7d5cf2c0e3edb5  -

为了让随机数统一,可以统一使用md5sum或者sha1sum等校验命令处理。

6 select 循环语句介绍及语法

select循环语句的主要作用可能就是创建菜单。

在执行带select循环语句的脚本时,输出会按照数字顺序的列表显示一个菜单项,并显示提示符(默认是#?),同时等待用户输入数字进行选择。

下面就来带大家看看生成菜单项的语法及具体案例实践。

第一种for循环语句为变量取值型,语法结构如下:

select 变量名 [ in 菜单取值列表 ]
do指令...
done

此结构中“in 变量取值列表”可省略,省略时相当于使用 in "$@",使用for i就相当于使用for i in "$@"

在这种select循环语句的语法中,select关键字后面会有一个“变量名”:

  • 每次执行时,变量名从in关键字后面的变量取值列表中(以空格分隔)取一个,然后进人循环(do和done之间),执行循环内的所有指令,当执行到done时结束返回。
  • select循环执行后会出现菜单项等待用户选择(不会自动循环所有变量列表),而用户输人的只能是菜单项前面的数字序号,每输入一次对应的序号就会执行一次循环。
  • 之后“变量名”再继续取变量列表中取一个值,继续执行循环内的所有指令(do和done之间的指令),当执行到done时结束返回。
  • 以此类推。
  • select是一个没有终止的循环,除非选择某个值时执行了退出循环指令,才会退出select循环;否则select需要会一直执行下去。
  • select如何遍历列表,完全取决于用户的选择,而for、while、until等是按顺序遍历列表。

select循环结构执行流程对应的逻辑图如下:
在这里插入图片描述

7 select 循环语句案例

示例1: 打印课程清单

[wsh@test ~ ✔]$ vim select1.sh
#!/bin/bash
select course in mysql python linux
doecho $course
done[wsh@test ~ ✔]$ bash select1.sh 
1) mysql
2) python
3) linux
#? 1
mysql
#? 2
python
#? 1
mysql
#? 1
mysql
#? 3
linux
#? ^C
# 按ctrl+c退出。

用while和case实现上面的select语句

#!/bin/bashfunction menu () {
echo -n '1) mysql
2) python
3) linux
#? '
}menu
read choicewhile true
docase $choice in1)echo mysqlread -p '#? ' choice;;2)echo pythonread -p '#? ' choice;;3)echo linuxread -p '#? ' choice;;'')menuread choice;;*)echoread -p '#? ' choice;;esac
done

示例2: 更改提示符,并配合case和exit使用

环境变量:

  • PS3,是select的选择提示符。
  • REPLY,是select选择的对应序号。
[wsh@test ~ ✔]$ cat select2.sh
#!/bin/bash
PS3="选择你的课程: "
select course in linux mysql python exit
doecho "你选择了第 $REPLY 个条目。"case $course inlinux)echo linux xxx;;mysql)echo mysql yyy;;python)echo python zzz;;exit)exit;;esacecho
done# 执行结果如下
[wsh@test ~ ✔]$ bash select2.sh 
1) linux
2) mysql
3) python
4) exit
选择你的课程: 1
你选择了第 1 个条目。
linux xxx选择你的课程: 2
你选择了第 2 个条目。
mysql yyy选择你的课程: 1
你选择了第 1 个条目。
linux xxx选择你的课程: 4
你选择了第 4 个条目。

示例3: 两个数计算器

[wsh@test ~ ✔]$ vim select3.sh 
#! /bin/bash
num1=10
num2=20
echo There are two numbers $num2 and $num1select method in 加法 减法 乘法 退出
docase $method in加法)echo $[ num1 + num2 ];;减法)echo $[ num2 - num1 ];;乘法)echo $[ num1 * num2 ];;退出)exit;;*)echo 从1-4中选择;;esac
done# 执行效果
[wsh@test ~ ✔]$ bash select3.sh
There are two numbers 20 and 101) 加法
2) 减法
3) 乘法
4) 退出
#? 1
30
#? 2
10
#? 3
200
#? 4
http://www.dtcms.com/a/349013.html

相关文章:

  • MATLAB 在工程仿真中的实践:以机械振动分析为例的完整流程
  • 1.Spring Boot:超越配置地狱,重塑Java开发体验
  • LeetCode 101 刷题 - (2) 第二章 玩转双指针
  • Jupyter Lab 常用快捷键清单
  • C++标准库头文件使用指南
  • 【C++】10. list
  • BUCK电路的环路补偿
  • JDK版本报错
  • 在PC机上使用虚幻引擎5(UE5)开发第一款游戏的完整入门指南
  • 门面设计模式
  • Python核心技术开发指南(012)——浮点数
  • 如何捕获组件的异常情况
  • 一个简单的html音乐播放器
  • 阿里发布Qoder:颠覆软件开发体验的AI编程平台
  • 前端应用容器化,基于Docker多阶段构建的最佳实践
  • More Effective C++ 条款05: 谨慎定义类型转换函数
  • Java 泛型的“擦除”与“保留”:一次完整的编译与反编译实验
  • Docker中Dify镜像由Windows系统迁移到Linux系统的方法
  • 【计算机408数据结构】第二章:基本数据结构之线性表
  • Leetcode 3660. Jump Game IX
  • 新的 Gmail 网络钓鱼攻击利用 AI 提示注入来逃避检测
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(十四)垂直滚动条
  • 【URP】[投影Projector]解析与应用
  • 【cs336学习笔记】[第6课]内核优化与Triton框架应用
  • 如何在算力时代乘风破浪?
  • 深度学习中的模型量化及实现示例
  • 【RAGFlow代码详解-4】数据存储层
  • MySQL学习记录-基础知识及SQL语句
  • 【零代码】OpenCV C# 快速开发框架演示
  • 在 Docker 容器中查看 Python 版本