Shell 编程下

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: Shell 编程下

安装expect工具

expect是自动化脚本解释型的工具

yum install expect -y

主要命令
    spawn 新建一个进程  这个进程是由expect控制
    send  发送字符串给expect控制的进程
    set   设置变量   set user root
    exp_continue 重新执行expect分支
    set timeout -1 设置超时时间 永远等待
    set timeout 10 设置超时时间 10秒
    interact 将脚本的控制权交给用户,用户继续使用shell执行命令

expect test.ex

#!/usr/bin/expect
set pass 123456
set user root
spawn ssh $user@10.0.1.10
expect {
"yes/no" { send "yes\r";exp_continue  }
"password" { send "$pass\r" }
}
interact

批量获取在线的IP地址 主机 进行批量秘钥分发

#!/bin/sh
#1.获取在线的主机 能ping通在线
>ip.txt
for i in 7 8
do
        ping -c1 -W1 10.0.0.$i &>/dev/null
        if [ $? -eq 0 ];then
           echo 10.0.0.$i >>ip.txt
        fi
done
#2.判断公钥是否生成
if [ ! -f ~/.ssh/id_rsa ];then
   ssh-keygen -P "" -f ~/.ssh/id_rsa
fi
#3.批量分发秘钥
pass=1
while read line
do
      /usr/bin/expect<<EOF
         set timeout 2
         spawn ssh-copy-id root@$line
         expect {
                "yes/no" { send "yes\r"; exp_continue }
                "password:" { send "$pass\r" };
         }
         expect eof
EOF
done<ip.txt

循环

for循环

语法
for 变量名 in 取值列表    {#取值列表可以是数字 字符串 序列 命令} 以空格分隔
do
     命令的集合
done
for 手 in 苹果 梨 香蕉 橘子  变量的值 依次从左到右读取
do
    echo 包裹${手}
done
包裹苹果
包裹梨
包裹香蕉
包裹橘子

案例1: 要求判断10.0.0.1-254网段的在线主机 能ping通则认为在线

注意: wait 等待上面的所有命令执行完成后才继续往下执行
#!/bin/sh
for i in {1..254}
do
     {
     IP=10.0.0.$i
     ping -c1 -W1 $IP &>/dev/null
     if [ $? -eq 0 ];then
     echo "ping $IP is ok"
     fi } &
done
wait
echo "在线取IP完成"

案例2: 使用for循环创建user.txt中的用户 附加 每个用户随机8位密码 用户名和密码统一输出到文件

user.txt
   zs
   ls
   oldboy
   alex
   lz
#!/bin/sh
for i in `cat user.txt`
do
   id $i &>/dev/null
   if [ $? -eq 0 ];then
         echo "useradd:$i already exists"
   else
          useradd $i &>/dev/null
          if [ $? -eq 0 ];then
                echo "create $i is ok"
          else
                echo "error"
          fi
         pass=`echo $((RANDOM))|md5sum|cut -c1-8`
         echo $pass|passwd --stdin $i &>/dev/null
         [ $? -eq 0 ] && echo "密码创建成功" || echo "密码创建失败"
         echo -e "$i\t$pass" >> pass.txt
    fi
done

for 循环笔试题

# 从1+100的和
#!/bin/bash
sum=0
for ((i=1;i<101;i++))
do
    ((sum+=i))
done
echo $sum
5050

案例:

企业项目实践机会(第6次)来了(本月中旬),但是,名额有限,队员限3人(班长带队)。

因此需要挑选学生,因此需要一个抓阄的程序

#!/bin/sh
>ran.txt
touch ran.txt
while true
do
RAN=`echo $((RANDOM%100+1))`
    if [ `grep -w $RAN ran.txt|wc -l` -eq 1 ];then
       continue
    fi
read -p "请输入你的姓名: " name
if [ $name = "exit" ];then
     echo "抓阄完毕统计结果如下"
     sort -rnk2 ran.txt 
     exit
else
    if [ `grep -w $name ran.txt|wc -l` -eq 1 ];then
    echo "抓过阄了不要闹了"
    continue
    else
    echo -e "$name\t$RAN"|tee -a ran.txt
    fi
fi
done

while 循环

while [ 条件测试 ]
do
  命令的集合
done
#!/bin/sh
while [ 10 -gt 10 ]
do
    sleep 1
    echo ok
done

while 批量创建用户

#!/bin/sh
while read user
do
    useradd $user &>/dev/null
    if [ $? -eq 0 ];then
    echo "ok"
    else
    echo "error"
    fi
done<user.txt
<user.txt 从文件中读取用户名 在循环里执行

Shell内置命令

exit 退出整个脚本
break 结束当前循环 或者跳出本层循环
continue 忽略本次循环剩余的代码,直接进入下一次循环
exit
[root@shell ~]# cat exit.sh
#!/bin/sh
while true
do
     echo hehe
     exit
     echo test
done
echo done......
break
[root@shell ~]# cat break.sh 
#!/bin/sh
while true
do
     echo hehe
     break
     echo test
done
echo done......
continue
[root@shell ~]# cat break.sh
#!/bin/sh
while true
do
     echo hehe
     continue
     echo test
done
echo done......

函数

函数的作用

1)命令的集合 完成特定功能的代码块
2)函数的优势可以使代码完全的模块化 便于复用 加强可读 易于修改
3)函数和变量类似 先定义才可调用,如果定义不调用则不执行 
定义函数
函数的传参
函数内的变量返回值     
return

定义函数

#!/bin/sh
fun1(){
        echo "第一种定义方式"
}
function fun2 {
        echo "第二种定义方式"
}
function fun3() {
        echo "第三种定义方式"
}
fun1      # 调用函数非常简单 只需要写函数名即可
fun2
fun3

函数传参

   1)函数名称后面跟字符串传参
[root@shell day5]# cat fun.sh 
#!/bin/sh
fun(){
     if [ -f $2 ];then
        echo "$2 exists"
     else
        return 5
     fi
}
fun /etc/hosts /etc/passwd
2)使用脚本的参数传参
[root@shell day5]# cat fun.sh
#!/bin/sh
fun(){
     if [ -f $1 ];then
        echo "$1 exists"
     else
        return 5
     fi
}
fun $2 $1
[root@shell day5]# sh fun.sh /etc/hosts /etc/passwd
/etc/passwd exists  

思考:

#!/bin/sh
fun(){
        num=10
        for i in `seq 10`
        do
           total=$[$i+$num]
        done
        echo "total的结果是: $total"
}
fun

传参

#!/bin/sh
#第一种定义方式
fun(){
        num=$1
        for i in `seq 10`
        do
           total=$[$i+$num]
        done
        echo "total的结果是: $total"
}
fun $2 $1
[root@shell day5]# sh fun.sh 20 30
total的结果是: 40

函数的变量

local num=20 只针对当前的函数生效 其他函数和语句无法接收local的变量

函数的返回值

#!/bin/sh
fun(){
      echo 100
      return 1
}
result=`fun`
echo "函数的状态码是: $?"
echo "函数的执行结果是: $result"
注意: $?上一条执行的如果有函数名称 则返回函数内的return值 如果不相关则上一条命令的返回值
#!/bin/sh
fun(){
      if [ -f $1 ];then
         return 50
      else
         return 100
      fi
}
fun $1
#根据函数的返回状态码进行输出结果
re=$?
#[ $re -eq 50 ] && echo "文件存在"
#[ $re -eq 100 ] && echo "文件不存在"
if [ $re -eq 50 ];then
        echo "文件存在"
elif [ $re -eq 100 ];then
        echo "文件不存在"
fi

案例: 文件统计行

line 内置变量 按行读取

[root@shell day5]# wc -l /etc/passwd
37 /etc/passwd
[root@shell day5]# cat /etc/passwd|wc -l
37
[root@shell day5]# cat while1.sh 
#!/bin/h
while read line
do
      let i++       
done</etc/passwd
echo $i
awk '{print NR}' /etc/passwd
sed '=' /etc/passwd|xargs -n2
grep -n . /etc/passwd
less -N /etc/passwd
cat -n /etc/passwd

数组

数组的分类

普通数组: 只能使用整数作为数组索引
关联数组: 可以使用字符作为数组索引 
元素=索引=下标
普通数组定义
[root@shell ~]# array[0]=shell
[root@shell ~]# array[10]=MySQL
[root@shell ~]# echo ${array[0]}
shell
[root@shell ~]# 
[root@shell ~]# echo ${array[10]}
MySQL
-----------------
[root@shell ~]# array=(shell MySQL Redis)
[root@shell ~]# echo ${array[0]}
shell
[root@shell ~]# echo ${array[1]}
MySQL
[root@shell ~]# echo ${array[2]}
Redis
----------------
[root@shell ~]# array=(Shell [5]=Docker Redis [10]=MySQL)
[root@shell ~]# echo ${array[0]}
Shell
[root@shell ~]# echo ${array[5]}
Docker
[root@shell ~]# echo ${array[6]}
Redis
[root@shell ~]# echo ${array[10]}
MySQL
---------------命令定义数组
[root@shell ~]# array=(`ls`)
[root@shell ~]# echo ${array[0]}
1.sh
[root@shell ~]# echo ${array[1]}
1.txt
[root@shell ~]# echo ${array[2]}
2.sh
[root@shell ~]# echo ${array[3]}
all.sh
常用的定义方式
array=(10.0.0.8 10.0.0.9 10.0.0.32)
取消定义数组
unset array 
如何查看数组
[root@shell ~]# echo ${array[0]}     # 使用索引查看
[root@shell ~]# echo ${array[*]}     # 查看数组中所有的值
shell MySQL Redis
[root@shell ~]# echo ${array[@]}     # 查看数组中所有的值
shell MySQL Redis
[root@shell ~]# echo ${!array[*]}     # 查看索引
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

案例:

#!/bin/sh
#定义数组
ip=(
10.0.0.1
10.0.0.2
10.0.0.7
10.0.0.8
10.0.0.9
)
#调用数组
for i in ${ip[*]}
do
      ping -c1 -W1 $i &>/dev/null
      [ $? -eq 0 ] && echo "ping $i 没问题....." || echo "ping $i 不通....."
done

遍历索引

#!/bin/sh
#定义数组
ip=(
10.0.0.1   0
10.0.0.2   1
10.0.0.7   2
10.0.0.8   3
10.0.0.9   4
)
#调用数组
for i in ${!ip[*]}
do
      ping -c1 -W1 ${ip[$i]} &>/dev/null
      [ $? -eq 0 ] && echo "ping ${ip[$i]} 没问题....." || echo "ping ${ip[$i]} 不通....."
done

关联数组 索引可以是字符串

[root@shell day5]# declare -A array
[root@shell day5]# array[index1]=shell
[root@shell day5]# array[index2]=mysql   
[root@shell day5]# array[index3]=redis      
[root@shell day5]# 
[root@shell day5]# echo ${array[index1]}
shell
[root@shell day5]# echo ${array[index2]}
mysql
[root@shell day5]# echo ${array[index3]}
redis
[root@shell day5]# echo ${array[*]}     
shell mysql redis
[root@shell day5]# echo ${array[@]}
shell mysql redis
[root@shell day5]# echo ${!array[@]}
index1 index2 index3
[root@shell day5]# array=([index1]=shell  [test]=Redis [index2]=Redis)
[root@shell day5]# echo ${array[*]}
shell Redis Redis
查看所有的当前shell定义的数组
declare -A

案例:

cat sex.txt

zs m

ls m

zp f

lw f

qq m

ww x

#!/bin/sh
#定义数组
declare -A array
while read sex
do
        let array[$sex]++
done<sex.txt
for i in ${!array[*]} 
do
        echo "性别$i 出现了 ${array[$i]} 次"
done
----------------
[root@shell day5]# sh array.sh
性别f 出现了 2 次
性别m 出现了 3 次
性别x 出现了 1 次

统计/etc/passwd 解释器出现的次数

#!/bin/sh
declare -A bash
while read line
do
     let bash[`echo $line|awk -F: '{print $NF}'`]++
done</etc/passwd
for i in ${!bash[*]}
do
        echo "$i 出现了 ${bash[$i]}次"
done

统计nginx日志ip出现的次数

#!/bin/sh
declare -A IP
while read line
do
     let IP[`echo $line|awk '{print $1}'`]++
done</var/log/nginx/access.log
for i in ${!IP[*]}
do
        echo "$i 出现了 ${IP[$i]}次"
done

案例: 反向破解随机数

思路:
1.知道RANDOM总共的随机数 32767
使用脚本 统计出RANDOM 总共多少个随机数
2.循环取MD5进行cut
3.和已知的MD5值进行比对 如果相等 则输出数字
# ? ? ?  动手试试
#!/bin/bash
. /etc/init.d/functions
declare -a array
for i in $(seq 0 32767)
do
   array[$i]=`echo $RANDOM|md5sum | cut -c 1-8`
done
keys=([0]=21029299 [1]=00205d1c [2]=a3da1677 [3]=1f6d12dd [4]=890684b)
action "mate" /bin/true
for key in ${keys[@]}
  do
  for i in `seq 0 32767`
  do
      if [[ "${array[i]}" = "$key" ]]; then
            echo "破解成功"     "密码:"$i------$key 
       action " " /bin/true
      fi
   done
done





















#!/bin/bash. /etc/init.d/functionsdeclare -a arrayfor i in $(seq 0 32767)do   array[$i]=`echo $RANDOM|md5sum | cut -c 1-8`donekeys=([0]=21029299 [1]=00205d1c [2]=a3da1677 [3]=1f6d12dd [4]=890684b)action "mate" /bin/truefor key in ${keys[@]}  do  for i in `seq 0 32767`  do      if [[ "${array[i]}" = "$key" ]]; then            echo "破解成功"     "密码:"$i------$key 
       action " " /bin/true      fi   donedone
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
2月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
18天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
1月前
|
Shell
Shell编程(下)
Shell编程(下)
88 1
|
1月前
|
Shell Linux Windows
Shell编程(上)
Shell编程(上)
40 1
|
1月前
|
Shell Linux 开发工具
|
1月前
|
监控 Unix Shell
shell脚本编程学习
【10月更文挑战第1天】shell脚本编程
65 12
|
2月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
2月前
|
存储 Unix Shell
shell脚本编程基础
【9月更文挑战第4天】
45 12
|
2月前
|
Shell Linux
Shell 编程 编写hello word
Shell 编写hello word
49 5