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条件语句的中文形象描述:
bash
# 如果男朋友努力工作,则继续相处
while 男朋友努力工作
do
继续相处
done
while 循环执行流程对应的逻辑图如下:

1.2 until 循环语句
until 循环语句的语法为:
bash
until <条件表达式>
do
指令...
done
until 循环语句的用法与while 循环语句的用法类似,区别是until会在条件表达式不成立时,进入循环执行指令;条件表达式成立时,终止循环。
为了便于大家记忆,下面是某女生写的until条件语句的中文形象描述:
bash
#如果男朋友不努力工作,就不继续相处
until 男朋友不努力工作
do
继续相处
done
until 循环执行流程对应的逻辑图如下:

2 当型和直到型循环的基本范例
示例1: 竖向打印54321
while格式:
bash
#!/bin/bash
i=5
while ((i>0))
do
echo $i
((i--))
done
until格式:
bash
#!/bin/bash
i=5
until ((i==0))
do
echo $i
((i--))
done
示例2: 计算1+2+3+...+99+100的和
bash
#!/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的阶乘
bash
#!/bin/bash
i=1
sum=1
while ((i<=5))
do
((sum*=i))
((i++))
done
echo "5的阶乘为:$sum"
示例4: 猴子吃桃。
- 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。
- 第二天早上又将第一天剩下的桃子吃掉一半,又多吃了一个。
- 以后每天早上都吃了前一天剩下的一半零一个。
- 到第 10 天早上想再吃时,发现只剩下一个桃子了。
问:一共有多少个桃子?
解题方法1: while 循环9次
bash
#!/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: 函数递归调用
bash
#!/bin/bash
function sum (){
if [[ $1 = 1 ]];then
echo $1
else
echo $[ ($(sum $[$1 -1]) + 1)*2 ]
fi
}
echo "猴子第一天摘的桃子数量是:$(sum 10)。"
示例5: 系统随机产生一个50以内数字,猜出该数字,并记录猜测次数。
bash
#!/bin/bash
# 生成随机数字,并保存到文件/tmp/number
random_num=$[ RANDOM%50+1 ]
echo "${random_num}" >> /tmp/number
# 记录猜测次数
i=0
while true
do
read -p "猜一猜系统产生的50以内随机数是:" num
if ((num>=1 && num<=50));then
((i++))
if [ $num -eq ${random_num} ];then
echo "恭喜你,第$i次猜对了!"
# 清理临时文件
rm -f /tmp/number
exit
else
echo -n "第$i次猜测,加油。"
[ $num -gt ${random_num} ] && echo "太大了,往小猜。" || echo "太小了,往大猜。"
fi
else
echo "请输入一个介于1-50之间的数字。"
fi
done
在实际工作中,一般会通过客户端SSH连接服务器,因此可能就会有在脚本或命令执行期间不能中断的需求,若中断,则会前功尽弃,更要命的是会破坏系统数据。
下面是防止脚本执行中断的几个可行方法:
-
使用
sh /server/scripts/while_01.sh &
命令,即使用&
在后台运行脚本。 -
使用
nohup /server/scripts/uptime.sh &
命令,即使用nohup
加&在后台运行脚本。 -
利用
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 满负荷工作
bash
#!/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
bash
[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 ]
do
bash /home/wsh/cpu_load &
((i++))
done
示例2: 控制并发数量不能超过CPU数量
bash
[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
do
bash /home/wsh/cpu_load &
# 控制并发数量不能大于cpu数量
while true
do
jobs=$(jobs -l |wc -l)
if [ $jobs -ge $cpu_count ];then
# 如果并发数大于cpu数量,则sleep 3s后继续检测
sleep 3
else
# 如果并发数小于cpu数量,则退出当前while 循环的并发检测
break
fi
done
done
wait 指令
等后台任务运行完成。
bash
#!/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秒输出一次系统负载(负载是系统性能的基础重要指标)情况。
bash
[wsh@test ~ ✔]$ cat while1.sh
#!/bin/bash
while true
do
uptime
sleep 2
done
[wsh@test ~ ✔]$ bash while1.sh
20:38:57 up 5:06, 2 users, load average: 0.00, 0.01, 0.05
20:38:59 up 5:06, 2 users, load average: 0.00, 0.01, 0.05
20:39:01 up 5:06, 2 users, load average: 0.00, 0.01, 0.05
20: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
do
uptime >> /tmp/loadaverage.log
sleep 2
done
# 放到后台运行
[wsh@test ~ ✔]$ bash while2.sh &
[wsh@test ~ ✔]$ tail -f while2.sh
示例2: 后台检测sshd服务,如果未运行,则重启sshd服务。
while格式:
bash
#!/bin/bash
while true
do
systemctl is-active sshd.service &>/dev/null
if [ $? -ne 0 ];then
systemctl restart sshd.service &>/dev/null
fi
sleep 5
done
until格式:
bash
#!/bin/bash
until false
do
systemctl is-active sshd.service &>/dev/null
if [ $? -ne 0 ];then
systemctl restart sshd.service &>/dev/null
fi
sleep 5
done
示例3: 使用while守护进程的方式监控网站,每隔3秒确定一次网站是否正常。
bash
[wsh@test scripts ✔]$ cat check_url.sh
#!/bin/bash
if [ $# -ne 1 ];then
echo "Usage: $0 url"
exit 1
fi
url="$1"
while true
do
if curl -o /dev/null -s --connect-timeout 5 $url;then
echo $url is ok.
else
echo $url is error.
fi
sleep 3
done
执行结果
bash
[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分钱时就不能再发短信了,提示"余额不足,请充值"
- 用户充值后可以继续发短信
bash
#!/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 ];then
echo "余额不足,请充值。"
# 余额不足,返回值为1
return 1
else
# 余额充足,返回值为0
return 0
fi
}
# 充值函数
function chongzhi () {
read -p "充值金额(单位:元):" chongzhi_money
while true
do
check_digit $chongzhi_money
if [ $? -eq 0 ] && [ ${chongzhi_money} -ge 1 ];then
money=$( echo "($money+${chongzhi_money})"|bc)
echo "当前余额为:$money"
return 0
else
read -p "重新输入充值金额:" chongzhi_money
fi
done
}
# 发送消息函数
function send_msg () {
# 检查余额是否充足
check_money
# 返回值与0比较,判定余额是否充足
if [ $? -eq 0 ];then
read -p "msg: " message
echo "$message" >> ${msg_file}
# bc计算器计算的结果,如果值小于1,则前面的0省略
new_money=$(echo "scale=2;($money*100-15)" | bc |cut -d. -f1 )
if [ ${new_money} -ge 100 ];then
money=$(echo "scale=2;${new_money}/100" | bc )
else
money=0$(echo "scale=2;${new_money}/100" | bc )
fi
echo "当前余额为:$money"
fi
}
# 主程序
while true
do
print_menu
echo
read -p "请输入你的选择:" choice
clear
case $choice in
1)
check_money_all
;;
2)
send_msg
;;
3)
chongzhi
;;
4)
exit
;;
*)
echo "只能从1、2、3、4中选择。"
;;
esac
echo
done
5 while 循环按行读文件的方式总结
示例:读取/etc/hosts内容
bash
[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 循环处理。
bash
#!/bin/bash
exec < /etc/hosts
while read line
do
echo $line
done
- 方式2:使用cat读取文件内容,然后通过管道进入while 循环处理。
bash
#!/bin/bash
cat /etc/hosts | while read line
do
echo $line
done
- 方式3:在while 循环结尾done处通过输入重定向指定读取的文件。
bash
#!/bin/bash
while read line
do
echo $line
done < /etc/hosts
- 方式4:定义shell分隔符为换行符
bash
#!/bin/bash
IFS=$'\n'
for line in $(cat /etc/hosts)
do
echo $line
done
6 while 循环和 until 循环小结
- while 循环结构及相关语句综合实践小结
- while 循环的特长是执行守护进程,以及实现我们希望循环持续执行不退出的应用,适合用于频率小于1分钟的循环处理,其他的while 循环几乎都可以被后面即将要讲到的for循环及定时任务crond功能所替代。
- case语句可以用if语句来替换,而在系统启动脚本时传入少量固定规则字符串的情况下,多用case语句,其他普通判断多用if语句。
- 一句话场景下,if语句、for语句最常用,其次是while(守护进程)、case(服务启动脚本)。
- Shell脚本中各个语句的使用场景
- 条件表达式,用于简短的条件判断及输出(文件是否存在,字符串是否为空等)
- if取值判断,多用于不同值数量较少的情况。
- for最常用于正常的循环处理中while多用于守护进程、无限循环(要加sleep和usleep控制频率)场景。
- case多用于服务启动脚本中,打印菜单可用select语句,不过很少见,一般用cat的here文档方法来替代。
- 函数的作用主要是使编码逻辑清晰,减少重复语句开发。
for 和 select 循环语句的应用实践
for循环语句和while循环语句类似,但for循环语句主要用于执行次数有限的循环,而不是用于守护进程及无限循环。for循环语句常见的语法有两种,下面将在不同的语法中对for循环语句进行详尽的讲解。
1 for 循环语法结构
1.1 变量取值型
第一种for循环语句语法结构如下:
bash
for 变量名 in 变量取值列表
do
指令...
done
在此结构中"in 变量取值列表"可以省略,省略时相当于in "$@"
,也就是使用 for i
就相当于使用for i in "$@"
。
这种for循环语句执行过程如下:
- for关键字后面会有一个"变量名",变量名依次获取in关键字后面的变量取值列表内容(以空格分隔)。
- 每次仅取一个,然后进入循环(do和done之间的部分)执行循环内的所有指令,当执行到done时结束本次循环。
- 之后,"变量名"再继续获取变量列表里的下一个变量值,继续执行循环内的所有指令,当执行到done时结束返回。
- 以此类推,直到取完变量列表里的最后一个值并进入循环执行到done结束为止。
1.2 C 语言型
第二种for循环语句称为C 语言型for循环,语法结构如下:
bash
for ((expl;exp2;exp3))
do
指令...
done
此种循环语句和while循环语句类似,但语法结构比while循环更规范、工整。
这种for循环语句说明如下:
-
for关键字后的双括号内是三个表达式:
-
第一个是变量初始化(例如:i=0)
-
第二个为变量的范围(例如:i<100)
-
第三个为变量自增或自减(例如:i++)。
-
-
当第一个表达式的初始值符合第二个变量的范围时,就进入循环执行;条件不满足时就退出循环。
for循环结构执行流程对应的逻辑图如下:

2 for 循环语句的基础实践
示例1:竖向升序打印
bash
# 列表型
[wsh@test ~ ✔]$ vim for1.sh
#!/bin/bash
for i in {1..5}
do
echo $i
done
[wsh@test ~ ✔]$ bash for1.sh
1
2
3
4
5
[wsh@test ~ ✔]$ vim for2.sh
#!/bin/bash
for i in $(seq 5)
do
echo $i
done
# c语言型
[wsh@test ~ ✔]$ vim for3.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
echo $i
done
# while型
[wsh@test ~ ✔]$ vim while1.sh
#!/bin/bash
i=1
while ((i<=5))
do
echo $i
((i++))
done
示例2:竖向降序打印
bash
[wsh@test ~ ✔]$ vim for4.sh
#!/bin/bash
for i in {5..1}
do
echo $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)
do
echo $i
done
示例3:求和、求乘积
bash
#!/bin/bash
sum=0
for i in {1..10}
do
sum=$[ sum + i ]
done
echo $(seq -s '+' 10)=$sum
bash
#!/bin/bash
sum=1
for i in {1..10}
do
((sum*=i))
done
echo $(seq -s '*' 10)=$sum
示例4:求水鲜花数
水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身。
bash
#!/bin/bash
for num in {100..999}
do
n1=$[num/100]
n2=$[num%100/10]
n3=$[num%10]
if [ $[ n1**3 + n2**3 + n3**3 ] -eq $num ];then
echo $n1^3 + $n2^3 + $n3^3 = $n1$n2$n3
fi
done
示例5:九九乘法表
bash
#!/bin/bash
for num1 in {1..9}
do
for ((num2=1;num2<=num1;num2++))
do
echo -en "$num2*$num1=$[ num2 * num1 ]\t"
done
echo
done
3 for 循环语句的企业级案例
示例1: 批量修改文件扩展名(把txt改成jpg)
bash
[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)
do
new_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: 批量设置服务开启启动
bash
#!/bin/bash
for service in crond atd chronyd
do
systemctl enable $service
done
示例3: 批量重启多个主机sshd服务
bash
#!/bin/bash
for host in server{1..10}
do
ssh root@$host systemctl restart sshd
done
示例4: 批量备份文件
bash
#!/bin/bash
for file in host*
do
cp $file /backup/${file}.bak;
done
4 for 循环语句的企业高级实战案例
bash
# 准备mariadb数据库
[wsh@test scripts ✔]$ sudo yum install -y mariadb-server
[wsh@test scripts ✔]$ sudo systemctl start mariadb
示例1: 实现 MySQL库备份的脚本
创建数据库脚本
bash
[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
执行效果
bash
[wsh@test scripts ✔]$ bash create_dbs.sh
[wsh@test scripts ✔]$ mysql -uroot -e 'show databases;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| web1 |
| web2 |
+--------------------+
备份数据库脚本
bash
[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
执行效果
bash
[wsh@test scripts ✔]$ bash dump_dbs.sh
[wsh@test scripts ✔]$ ls *sql
web1.sql web2.sql
示例2: 实现 MySQL分库分表备份的脚本
创建表脚本
bash
[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
执行结果
bash
[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 |
+------+----------+
备份表脚本
bash
[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
执行效果
bash
[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来猜出具体结果了。
bash
[wsh@test ~ ✘]$ echo "wsh$RANDOM"|md5sum |cut -c 1-8
d3a8a340
方法2: 通过openssl产生随机数,结果中包涵字母大小写和数字更加安全。
bash
[wsh@test ~ ✔]$ openssl rand -base64 8
Szp2fJ/C7tk=
[wsh@test ~ ✔]$ openssl rand -base64 20
pIELp8BUyTtRIE3v/GNrAijQBLU=
方法3: 通过date命令获得随机数,%N输出纳秒(nanoseconds)。
bash
[wsh@test ~ ✔]$ date +%s%N
1756039707120616853
[wsh@test ~ ✔]$ date +%s%N
1756039710419740788
方法4: 通过设备/dev/urandom或/dev/random和md5sum生成随机数。
这两个设备存储着系统当前运行的环境的实时数据。它可以看作是系统某个时候,唯一值数据,因此可以用作随机数元数据。我们可以通过文件读取方式,读得里面数据。
-
/dev/urandom,返回指定请求数量的随机数,如果请求的数量非常庞大的话,返回的随机数可能是伪随机数,随机数质量稍差些。即使如此,它们对大多数应用来说已经足够了。
-
/dev/urandom,也是返回指定请求数量的随机数,但是它产生的随机数质量很高, 是属于真随机数, 主要用于需要高质量的随机数的地方,比如:生成加密密钥等。
为了保证随机数的质量,
/dev/random
只能返回熵池当前最大可用的随机二进制位,当请求超过这个值,就会阻塞,直到熵池中有足够的随机二进制位。
bash
[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码都是互联网整个服务器网络中唯一的编码。它的原信息会加人硬件、时间、机器当前运行信息等。
bash
[wsh@test ~ ✔]$ cat /proc/sys/kernel/random/uuid
7323c4ed-8256-45bd-a8f7-8e36e1e03a74
[wsh@test ~ ✔]$ uuidgen
21258f54-61e2-46af-9abf-a4fbb34bbcd5
方法6: 使用expect附带的mkpasswd命令生成随机数。
bash
[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生成随机数。
bash
[wsh@test ~ ✔]$ mktemp -u
/tmp/tmp.3XfWcblZDc
[wsh@test ~ ✔]$ mktemp -u |sha1sum
740fdd67d699071126c52daa1a7d5cf2c0e3edb5 -
为了让随机数统一,可以统一使用md5sum或者sha1sum等校验命令处理。
6 select 循环语句介绍及语法
select循环语句的主要作用可能就是创建菜单。
在执行带select循环语句的脚本时,输出会按照数字顺序的列表显示一个菜单项,并显示提示符(默认是#?),同时等待用户输入数字进行选择。
下面就来带大家看看生成菜单项的语法及具体案例实践。
第一种for循环语句为变量取值型,语法结构如下:
bash
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: 打印课程清单
bash
[wsh@test ~ ✔]$ vim select1.sh
#!/bin/bash
select course in mysql python linux
do
echo $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语句
bash
#!/bin/bash
function menu () {
echo -n '1) mysql
2) python
3) linux
#? '
}
menu
read choice
while true
do
case $choice in
1)
echo mysql
read -p '#? ' choice
;;
2)
echo python
read -p '#? ' choice
;;
3)
echo linux
read -p '#? ' choice
;;
'')
menu
read choice
;;
*)
echo
read -p '#? ' choice
;;
esac
done
示例2: 更改提示符,并配合case和exit使用
环境变量:
- PS3,是select的选择提示符。
- REPLY,是select选择的对应序号。
bash
[wsh@test ~ ✔]$ cat select2.sh
#!/bin/bash
PS3="选择你的课程: "
select course in linux mysql python exit
do
echo "你选择了第 $REPLY 个条目。"
case $course in
linux)
echo linux xxx
;;
mysql)
echo mysql yyy
;;
python)
echo python zzz
;;
exit)
exit
;;
esac
echo
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: 两个数计算器
bash
[wsh@test ~ ✔]$ vim select3.sh
#! /bin/bash
num1=10
num2=20
echo There are two numbers $num2 and $num1 。
select method in 加法 减法 乘法 退出
do
case $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 10 。
1) 加法
2) 减法
3) 乘法
4) 退出
#? 1
30
#? 2
10
#? 3
200
#? 4