shell编程:完成一个简单的不重复抽取且自动重新开始自动抽奖脚本
文章目录
前言:脚本的目标与分析
脚本的目标:
脚本的分析:
一、 实现脚本的大致步骤
脚本环境:
step1:文件的建立
step2:抽奖功能的实现
step3:不重复抽取功能的实现
step4:抽完自动重新开始的实现与step3的优化
二、用vim完成脚本(version1)
三、脚本的调试与优化
(1)文件异常的处理办法(version-1.1)
(2)连续抽奖的办法(vision-1.1的改良与部署)
四、脚本的其他思路
前言:脚本的目标与分析
脚本的目标:
实现一个类似于上课点名的抽奖脚本,抽过的人在本轮中不会重复出现,直到抽完为止,且抽完所有人后自动开始重新抽取。
脚本的分析:
由目标可知,脚本需要具备的主要功能为以下几点:
1.实现简单的抽奖功能
2.抽奖每轮不重复
3.抽完一轮后自动重新开始
抽奖功能我们可以用随机数RANDOM来实现,假如一个班有50个同学,则在文件内对应50个编号,我们可以用((RANDOM%50 + 1))来随机出这50个编号(RANDOM%50求余可以得出0到49的随机数,我们在此基础上加一即可得到1~50的随机数),而抽到的编号我们可以在另一个文件内记录,之后每次判断随机数是否在抽过的编号文件内出现,如果没有出现则代表这个同学没有被抽过。
而抽完之后自动重新开始这个功能我们可以先判断所有同学是否都被抽到过,只要我们确保每个同学不会被重复选取则当两个文件内容数量相等,则代表着所有同学都被抽过一次了。然后只要我们把抽过名单清空,则可以开始新一轮抽奖。
一、 实现脚本的大致步骤
脚本环境:
centos7 bash 4.2.46(2)-release (x86_64-redha
t-linux-gnu) vim编辑器
step1:文件的建立
我们先创建一个用于测试的名单文件name.txt并往里面输入几个名字
cat >> name.txt <<EOF
> 刘一
> 陈二
> 张三
> 李四
> 王五
> 赵六
> 孙七
> 周八
> 吴九
> 郑十
> EOF
step2:抽奖功能的实现
先完成一个基础的抽奖:
因为名单内的名字都是以行为单位的,我们可以认为,总行数即为总人数,我们可以用cat和wc -l 的组合命令求得总人数,同理可以求出被抽过的人数。我们用num_total来表示总人数。用num_lucky来表示被抽过的人数。
num_total=$(cat name.txt|wc -l) #定义num_total为抽奖的总人数
num_lucky=$(cat lucky.txt|wc -l) #定义num_lucky为被抽过的人数
因此我们需要1~num_total的随机数num,即
num=$((RANDOM%(num_total)+1))
然后我们可以用head和tail语句定位那个随机编号num
cat name.txt|head -$num|tail -1
#假设num=5,则上述输出的是头五行的最后一行,即第五行
我们可以实现一个最基础的抽奖脚本
num_total=$(cat name.txt|wc -l)
num=$((RANDOM%(num_total)+1))
echo 恭喜"$(cat name.txt|head -$num|tail -1)"中奖!
step3:不重复抽取功能的实现
新建一个文件用来存放被抽过同学的编号,在抽取随机数的时候,判断随机数在被抽过同学文件是否出现,如果没出现过则代表改随机数对应编号的同学没被抽取过,然后我们把这个编号写入被抽取过的名单里,然后输出结果。相反的,则我们继续抽取随机数。
while(true)
donum_total=$(cat $name.txt|wc -l) num=$(($RANDOM % $num_total + 1 ))if [[ -z "$(cat lucky.txt|grep $num)" ]]#用cat lucky.txt|grep $num 过滤出num值,再用-z判断是否存在thenecho 恭喜"$(cat lucky.txt|head -$num|tail -1)"中奖! echo $num>>lucky.txtbreakelsecontinuefi
done
其中[ -z STRING ] “STRING” 的长度为零则为真,与test -z 相等
这样我们就完成了不重复抽取同学的功能,但是一旦写满将一直不满足if条件会进入else命令,则会进入死循环。
step4:抽完自动重新开始的实现与step3的优化
在step3的实际操作中我们发现当总人数大于10时,我们抽几次后可能会陷入死循环,总是永远抽不到刘一。这是因为当例如1和10这样的数同时存在当10先被抽到并且写入到被抽过名单内,再次执行抽到1时if判断那里grep过滤1的时候同样会将10过滤出来因此程序判定1被抽到过,1不会被写入。而随着数量进一步增多,这个现象会更加频繁,因此我们可以用正则表达式^$num$来唯一表达num值来解决这一问题(^char 以char开头的字符 // char$ 以char结尾的字符)
↑↑↑(就是抽不到刘一)
由一开始的脚本分析我们可以知道当两个文件内容数量相等,则代表着所有同学都被抽过一次了。然后只要我们把抽过名单清空,则可以开始新一轮抽奖。
> lucky.txt #清空抽过的名单
因此我们只要在step3的循环外再加一个判断即可。
if (( $num_total==$num_lucky )) #判断是否全部抽完
then> lucky.txt #清空抽过的名单并输出抽完提示echo $"全都抽完啦!请再抽一次重新开始"break
另外,我们把name.txt改为位置变量$1即可运用在不同文件上
二、用vim完成脚本(version1)
在vim编辑器内完成脚本如下:
#!/bin/bash #声名解释器
touch lucky.txt #新建被抽过人的文件
while(true) #主循环
do
num_total=$(cat $1|wc -l) #定义num_total为抽奖的总人数
num_lucky=$(cat lucky.txt|wc -l) #定义num_lucky为被抽过的人数
if (( $num_total==$num_lucky )) #判断是否全部抽完
then> lucky.txt #清空抽过的名单并输出抽完提示echo $"全都抽完啦!请再抽一次重新开始"break
elsenum=$((RANDOM%(num_total)+1)) #定义num为随机数if [[ -z "$(cat lucky.txt|grep ^$num$)" ]] #判断是否没抽过thenecho $num>>lucky.txt #将没抽过的人编号输入抽过的名单echo 恭喜"$(cat $1|head -$num|tail -1)"中奖! breakelsecontinue #如果抽过重新开始主循环重新抽取fi
fi
done #结束
脚本测试:
三、脚本的调试与优化
(1)文件异常的处理办法(version-1.1)
当我们不小心或者是在被抽过名单内加入了一些元素,有时会导致脚本的不可运行
↑↑↑(脚本陷入了死循环)
这是因为在写第一个if判断的时候只考虑了抽过名单数小于或等于总名单的情况,而未考虑大于的情况,在正常使用中的确可以正常运行,而当抽过名单文件陷入异常(大于总名单)时,且当编号在抽过名单中全部出现过后,文件不会得到清空,脚本会一直抽取随机数从而陷入死循环。
因此我们只需要把第一个if判断中的等于改为小于等于即可。
if (( $num_total<=$num_lucky )) #当所有人都被抽过或文件陷入异常时
(2)连续抽奖的办法(vision-1.1的改良与部署)
当我们需要连续多次抽奖时,每抽一个人都需要执行一次脚本。我们希望脚本可以实现可连续抽取,随时退出。
我们只需要把第二个if判断后的break去掉,加入一个交互命令即可。
if [[ -z "$(cat chouguo.txt|grep ^$num$)" ]]
thenecho "$num" >>luckylist.txtecho "恭喜$(cat $1|head -$num|tail -1)中奖!"#breakread -p "请敲任意键继续" #把break注释掉,加入一个交互命令
同时我们再给脚本可执行权限同时引入到bin目录下面
chmod +x choujiang.sh
cp choujiang.sh /bin
我们在/root/.bashrc下给脚本定义一个永久别名
刷新文件
source /root/.bashrc
这样我们的脚本就部署好了。
四、脚本的其他思路
上述脚本的思路就是在另一个空文件内做加法,把抽过的人的编号加到那个空文件内去,等到所有人都到那个空文件内去了我们再重新开始。
其实我们也可以先把所有人先复制到另一个文件中,每抽到一个人就用sed命令删除,等到文件为空的时候就说明所有人都被抽取过了,再把名单复制过去又可以重新开始。
事实上第二种的思路实现起来更为方便简洁,就留给大家去思考实现了。
shell编程:完成一个简单的不重复抽取且自动重新开始自动抽奖脚本相关推荐
- netfilter编程实例——一个简单的防火墙
一.iptables防火墙netfilter介绍 Linux 防火墙包含两部分,内核 netfilter 和用户空间工具 iptables.管理员通过 iptables 工具集和内核打交道,将防火墙规 ...
- 用Shell编程写一个能实现自动安装目录和运行游戏的脚本
By:C_linux-yu 用Shell编程写一个能实现自动安装目录和运行游戏的脚本 设计框架 :使用宏定义保存目录路径,方便切换 封装页面函数,目录安装函数,游戏运行函数供调用 主体使用while, ...
- 用switch语句编程设计一个简单的计算器程序
用switch语句编程设计一个简单的计算器程序. 要求根据用户从键盘输入的表达式(注意操作数与运算符之间没有空格): 操作数1 运算符op 操作数2 计算表达式的值,指定的算术运算符为加(+).减(- ...
- 编程设计一个简单的计算器程序,要求根据用户从键盘输入的表达式,操作数
编程设计一个简单的计算器程序,要求根据用户从键盘输入的表达式,操作数 首先,先写出各类计算的函数,参数从主函数中提取,返回计算后所得的值 因计算器不只要求能计算加减乘除,所以所有函数类型都为doubl ...
- 编程设计一个简单的计算器程序
要求 用switch语句编程设计一个简单的计算器程序.要求根据用户从键盘输入的表达式. 操作数1 运算符op 操作数2 计算表达式的值.指定的算术运算符为加(+).减(-).乘(*).除(/). 当除 ...
- 编写用switch语句编程设计一个简单的计算器程序
编程要求 根据提示,在右侧编辑器补充代码.要求用switch语句编程设计一个简单的计算器程序.要求根据用户从键盘输入的表达式. 操作数1 运算符op 操作数2 计算表达式的值.指定的算术运算符为加(+ ...
- c语言12之编程设计一个简单的计算器程序,要求根据用户从键盘输入的表达式:操作数1 运算符op 操作数2 计算表达式的值,指定的运算符为加减乘除。
题目: 设计一个简单的计算器程序,要求根据用户从键盘输入的表达式: 操作数1 运算符op 操作数2 计算表达式的值,指定的运算符为加减乘除. 源代码: #include<stdio.h> ...
- shell编程:定义简单标准命令集
shell是用户操作接口的意思,操作系统运行起来后都会给用户提供一个操作界面,这个界面就叫shell,用户可以通过shell来调用操作系统内部的复杂实现,而shell编程就是在shell层次上进行编程 ...
- 寒江独钓Windows内核安全编程__一个简单的Windows串口过滤驱动程序的开发
在Windows系统上与安全软件相关的驱动开发过程中,"过滤(filter)"是极其重要的一个概念.过滤是在不影响上层和下层接口的情况下,在Windows系统内核中加入新的层,从而 ...
最新文章
- 毕业后想拿大厂 Offer?你得完整拥有这些计算机知识体系!
- 三个基于.net的浏览器内核使用的比较
- 转:写的不错的eclipse配置cdt的文章
- [C# 基础知识系列]专题六:泛型基础篇——为什么引入泛型
- 祝福!微软 46 周年生日快乐!
- 第1节 连通性强连通、割点和桥(一)
- 2021年春季学期期末统一考试 保险学概论 试题
- java创建一个成员方法吗,java构造方法和成员方法的区别
- Microsoft.AspNet.Identity 自定义使用现有的表—登录实现
- 高级语言的编译过程和解释过程_进来了解一下C语言真正的编译过程看你掌握了吗?...
- 参加软件测试工程师面试前,这些内容你一定要准备
- 使用excel2003中的solver解决最优化问题
- Lucene学习入门——核心类API
- 美式期权损益图matlab,期权损益图的画法
- java redis hscan_如何在Redis中使用HSCAN命令?
- 小学认识计算机说课ppt,《认识计算机》说课稿.ppt
- python 正则re模块 group() groups()
- 算法7:求用小矩形覆盖大矩形有多少种方式
- 用C语言编辑一光年相当于多少米,一光年到底有多远?是光速跑了365天的距离,这样说你就少算了...
- u8服务器ip地址在哪修改,u8服务器ip地址在哪修改