三剑客实战抽奖

抽奖规则

共抽出6名获奖学员,1名50元,5名各10元。获奖同学在微信群里找班主任领取奖励。

wx.txt 文件路径

/tmp/wx.txt.zdh1

10元

secret よう..じょ 若 M.X.Y 叫我三胖就好

50元

正常的程序

rand(){
  local count
  local seeds
  count=0
  seeds=`while read line;do echo ${line// /..}; done < wx.txt`
  while [[ $count != 1 ]];do
	  seeds=`for seed in $seeds;do (($RANDOM%2==0)) && echo $seed;done`
      count=`echo "$seeds" | wc -l`
  done
  if [[ $seeds == "" ]];then
    rand
  elif [[ $seeds != "" ]];then
	  echo $seeds
  fi
}


is_repeat(){
  for arr in ${arrs[@]};do
    if [[ $arr == $1 ]];then
      echo 0
      return 0
    fi
  done
  echo 1
}


main(){
  for i in `eval echo {1..$1}`;do
    tmp=`rand`
    while [[ `is_repeat $tmp` == 0 ]];do
      tmp=`rand`
    done
    arrs[$i]=$tmp
  done
  echo ${arrs[@]}
}


main $1

有bug的程序

rand(){
    local count
    local seeds
    local name1
    local seed
    count=0
    name1=`while read line;do echo ${line// /..};done < wx.txt`
    # name1 变量和seeds变量要一样,不然下面的while循环就会一直使用seeds变量的所有内容,内容就不会减少,造成死循环。while循环判断只有一行内容的时候才会停止循环。
    while [[ $count != 1 ]];do
      seeds=`for seed in $name1;do (($RANDOM%2==0)) && echo $seed;done`
      echo $seed
      # echo 打印$seeds值,没有添加双引号,所有的值都会放到一行里面,使用双引号就会每个值单独一行显示。
      #count=`echo $seeds |wc -l`
      count=`echo "$seeds" |wc -l`
      #count=1
      echo "还有多少学员:" $count
    done

    if [[ $seeds == "" ]];then
      rand
    elif [[ $seeds != "" ]];then
      echo $seeds
    fi
}


is_repeat(){
  for arr in ${arrs[@]};do
    if [[ $arr == $1 ]];then
      echo 0
      return 0
    fi
  done
  echo 1
}

main(){
  for i in `eval echo {1..$1}`;do
    tmp=`rand`
    while [[ `is_repeat $tmp` == 0 ]];do
      tmp=`rand`
    done
    arrs[$i]=$tmp
  done
  echo ${arrs[@]}
}

main $1

问题1:变量命名问题,变量需要重复使用。
问题2:没有关注到echo "$seeds",与 echo $seeds差别。

抽奖小程序

方法1

# 将wx.txt.zdh1的内容转化成数组
# 数组下标计数
count=0
# 将文件中的内容逐行存入数组
while read line
        do
        seeds[$count]=$line
        let "count++"
        # let "count++"可以换成count=$[$count+1]
        done<wx.txt.zdh1

# 从数组中随机取一个值并删除被取出的值
for ((i=1;i<=$1;i++))
        do
        total=${#seeds[@]}
        index=$[$RANDOM % ${#seeds[@]}]
        echo ${seeds[$index]}
        unset seeds[$index]
done

方法2

is_repeat的arrs是从main函数传进来的,第一次arrs为空数组,is_repeat会返回1,然后main函数中会执行第一次取值。

# 从wx.txt.zdh1文件中随机取一个名字
getName(){
# 数组下标计数
local count
count=0

# 将文件中的内容逐行存入数组
while read line
do
seeds[$count]=$line
let "count++"
# let "count++"可以换成count=$[$count+1]
done<wx.txt.zdh1

total=${#seeds[@]}
index=$[$RANDOM % ${#seeds[@]}]
echo ${seeds[$index]}
}
# 判断取出来的值是否有重复
is_repeat(){
        for arr in ${arrs[@]};do
          if [[ $arr == $1 ]];then
                echo 0
                return 0
          fi
        done
        echo 1

}

# 循环取N次值,N是$1,即用户输入的脚本参数
main(){
        for i in `eval echo {1..$1}`;do
          tmp=`getName`
          while [[ `is_repeat $tmp` == 0 ]];do
            tmp=`getName`
          done
        arrs[i]=$tmp
        done
        echo ${arrs[@]}
}

main $1

Shell编程:抽奖程序

#!/bin/bash
# 抽奖函数
raffle(){
    local count
    local raffle_list                                                                                   #定义局部变量
    count=0
    raffle_list=`while read line;do echo ${line// /..};done < student_list`                             #读取学员名单
    while [[ $count != 1 ]];do
        raffle_list=`for raffle_name in $raffle_list;do (($RANDOM%2 == 0)) && echo $raffle_name;done`   #for循环提取学员,随机数抽取获奖学员
        count=`echo "$raffle_list" | wc -l`                                                             #结束循环
    done
    if [[ $raffle_list == "" ]];then                                                                    #处理获奖学员为空情况;再抽一次
        raffle
    elif [[ $raffle_list != "" ]];then
        echo $raffle_list
    fi
}
#获奖学员去重
is_repeat(){
    for arr in ${arrs[@]};do
        if [[ $arr == $1 ]];then
            echo 0
            return 0
        fi
    done
    echo 1
}
main(){
    for i in `eval echo {1..$1}`;do                                                                     #抽取1到$1位获奖学员
        tmp=`raffle`
        while [[ `is_repeat $tmp` == 0 ]];do
            tmp=`raffle`
        done
        arrs[$i]=$tmp
    done
    echo ${arrs[@]}
}
main $1

源程序:

程序运行:抽取一位获奖者

程序运行

程序运行:抽取五位获奖者

程序运行2

练习1:netstat统计tcp状态

netstat -t | awk 'NR>2{print $1,$6}' | sort | uniq -c

练习2:抽奖小程序

#!/bin/bash
array_rand(){
  num=0
  name=`while read line; do echo ${line// /..}; done < wx.txt.zdh1`
  #把文件中的名字存入到name数组中
  for i in $name; do
    arrs[$num]=$i
    num=$num+1
  done

  for i in `eval echo {1..$1}`; do
    #随机抽取数组的索引,索引对应的名字即为抽中的名字,随机生成1到数组长度之间的任意一个随机数
    rand=$(( (RANDOM%${#arrs[*]}) + 1 ))
    #去重,如果抽中相同的索引,则重新抽取
    while [[ `uniq $rand` == 0 ]]; do
      rand=$(( (RANDOM%${#arrs[*]}) + 1 ))
    done
    #把抽中的索引存入index数组中(该数组专门存放中奖的索引)
    index[$i]=$rand
    #把抽中索引对应的名字存入到lucky数组中(该数组专门存放中奖的名字)
    lucky[$i]=${arrs[$rand-1]}    
  done    
  echo ${lucky[*]}
}
             
#去重 
uniq(){
  for inde in ${index[*]}; do
    if [[ $inde == $1 ]]; then
      echo 0
      return 0
    fi
  done
  echo 1
}

array_rand $1
  • 抽奖结果
    image

抽奖程序
使用awk和for循环进行
1、用户输入抽奖次数
2、获取抽奖次数后,通过random取余文件的总行数,得到一个随机数
3、将该随机数作为行数,用awk进行读取该行内容,作为被抽中人员
4、将抽中的行删除,并进行下一次循环
程序如下:
image
问题:存在报错,说cannot rename,啥原因?
image

"$rand" 哪里来的?,使用 sed 做什么?

$ran是将随机获得的行数拿出来,加上d是表示使用sed -i 删除该行

sed 用法怎么用的?你这个使用变量的方式也有问题。/${ran}/d

/${ran}/d这种不是基于关键字匹配么,我在网上搜索是可以直接用我的这种方式来删除指定行的,老师您看一下我不太理解这种为啥不行
https://blog.csdn.net/wdz306ling/article/details/80087889

之前不知道这个 ran 是数字,"${ran} d"/tmp/twx.txt.zdh1 把文件复制到你的用户家目录下,不要去 /tmp 下修改,文件只有一份。你修改了别的同学就没法用了。

关闭