目的:主要是为了练习shell脚本的使用
1.首先在shell中创建一个抽奖名单,wx.txt文件,然后创建抽奖脚本,vim lottery.sh
![]()
2.编写脚本
@1.seed=`cat wx.txt`或者seed=$(cat wx.txt)
在shell中执行命令并赋值给变量有两种方式,另外一种方式是用$(),例如a=$(cat /etc/issue)
另外一种是使用反引号` `
1)在shell脚本中使用反引号时,他本身就对\做了一层转义,如果你有需要匹配的\的情况的话,需要再次进行转义。所以在反引号中,两个转义符才是进行转义!
2)$()中则不需要考虑\的问题,与我们平常使用的一样:\ = \。且自己转义后,他还是识别转义符。
3)反引号是老的用法,$()是新的用法,我们推荐使用$()
((2==2))&&echo “chenrourou" 如果前面为1,就输出后面的值,一定要用括号括起来,不括起来就什么都不是,不会进行计算的;
&&操作的特性:类似于短路,用与的用法来写代码就非常简洁,很多大佬都用这种方法;
@3. $RANDOM输出任意一个随机数,shell自带函数变量,记住就行;
@4.echo “$seed”加双引号和不加双引号的区别:
echo $seed(会打印成一行,每行以空格分隔开)
echo “$seed”(会按文件中原来样式,一行一行打印)
@5.bug1分析:如果名字中间有空格,读取wx.txt中内容时,就会默认分隔成两个名字,因此要将读取文件改为:
seeds=$(while read line; do echo ${line// /..};done <wx.txt)
${line// /..}//代表替换全局,这里代表将多有的空格用..替换
![]()
shell脚本编写一节有提到
bug2分析:$seed没加双引号,只能统计一行,加了双引号就能统计多行 , 这里的$seeds不是数组而是以空格为分隔的字符
bug3分析:输出有空白,为什么会有空白呢,因为有的时候可能随机数中全是奇数
3.改进脚本,分析以上bug,去掉空白的脚本如下:
1)为什么要加local呢?(一定要注意)
因为不加local的话 count和seeds在bash里默认是全局的,如果是全局的,有好几个函数来调用,如果有一个函数中把seeds和count里面的数改变了,这里其他函数也都会改变;因为rand函数要递归,因此需要加local防止递归对变量的改变;
虽然递归影响效率,可以转化为for循环,但是使用for循环会使用好多行代码,不如递归简单
2)(( ))和[[ ]]的区别
(( ))的语法,是计算的语法,能够进行加减乘除运算;[[ ]]是用来条件判断的
3) :set number可以显示vim编辑器的行号
永久配置行号参考该博客
键盘按“dd”运行vi删除行指令,之前光标移动的行被整行删除
4)while [[ $seeds == '' ]] 该条命令''中间咩有空格,要注意⚠️
4.为了防止抽中同一个同学多次,需要去重操作以及参数化
代码如下:
![]()
res(){
set=(1 2 3 4 5 6 7 8 9 10)
for i in ${set[@]};do (⚠️注意不能用for i in 10,但是可以遍历一个数组或者 文件)
tmp=$(rand)
while [[ $(is_repeat $tmp) ]];do
tmp=$(rand)
done
arrs[$i]=$tmp
done
echo ${arrs[@]}
}
先分析is_repeat()函数,这里抽到的人的名字与已经抽到的数组中的名字进行对比去重,${arrs[@]}为数组中的名单,对该名单进行遍历,判断如果抽到的人和名单中的名字重复,就输出0,负责遍历完(注意是遍历完⚠️)之后输出1;这里的$1是is_repeat()函数的形参而$tmp 是实参。
res()函数:对抽奖人数进行遍历(一次抽多少个中奖的人),$1执行rand函数并赋值给tmp变量,即将中奖的人的名字赋值给tmp变量;判断当中奖人的名字与中奖名单(数组)重复的时候,继续执行rand函数tmp=$(rand),直到抽到的人名字与中奖名单中的名字不重复,则执行arrs[$i]=$tmp,将中奖的人加入中奖名单中,直到循环$i次为止,就可以打印出这个数组了,即中奖名单!
最后调用 res $1
运行该脚本,结果如下:
![]()