shell入门(五)

目录

1、随机数

1、如何生成随机数

RANDOM,随机会产生0-32767的随机整数

产生一个随机数
[root@localhost ~]# echo $RANDOM
13214
产生0-10之间的随机数,只需要取余11
[root@localhost shellDemo]# echo $[RANDOM%11]
6
产生1-50之间的随机数
[root@localhost ~]# echo $[RANDOM%50+1]
35
产生10-99之间的随机数
[root@localhost ~]# echo $[RANDOM%90+10]
98
产生100-999的随机数
[root@localhost ~]# echo $[RANDOM%900+100]
914
产生50-100的随机数
[root@localhost ~]# echo $[RANDOM%51+50]

2、随机产生以139开头的电话号码

#! /bin/env bash

# 产生1000个以139开头的电话号码并保存文件phonenum.txt中

#文件值
file=/root/shellDemo/phonenum.txt

#循环
for((i=1;i<=1000;i++))
do
#每一个都取随机数,避免重复
        n1=$[RANDOM%10]
        n2=$[RANDOM%10]
        n3=$[RANDOM%10]
        n4=$[RANDOM%10]
        n5=$[RANDOM%10]
        n6=$[RANDOM%10]
        n7=$[RANDOM%10]
        n8=$[RANDOM%10]
#>>追加到文件中
        echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >>  $file
done

3、随机抽出5位幸运观众

具体需求:

  1. 在上面的1000个手机号里抽奖5个幸运观众,显示出这5个幸运观众。
  2. 但只显示头3个数和尾号的4个数,中间的都用*代替

① 思路

  1. 确定幸运观众所在的行 0-1000 随机找出一个数字 $[$RANDOM%1000+1]
  2. 将电话号码提取出来 head -随机产生行号 phonenum.txt |tail -1
  3. 显示前3个和后4个数到屏幕 echo 139****

② 落地实现

#! /bin/env bash
# 随机抽取2个幸运观众,并显示出来

#获取幸运观众个数
n=$1

#定义变量
phone=/root/shellDemo/phonenum.txt

#循环
for((i=1;i<=$n;i++))
do
        #确定文件行数,命令执行结果赋值给变量需要使用``包起命令来
        line=`wc -l $phone |cut -d ' ' -f1`
        #产生1-line之间的随机数
        num=$[RANDOM%$line+1]
        #将电话号码提取出来
        luck_num=`head -$num $phone |tail -1`

        #显示到屏幕,从第8位开始,截取4位,索引从0开始
        echo "139****${luck_num:7:4}"
        echo $luck_num >> luck.txt
        #删除已经被抽取的幸运观众
        sed -i "/$luck_num/d" $phone
done
[root@localhost shellDemo]# ./randomdemo2.sh 5
139****9240
139****2506
139****0196
139****5403
139****6964
139****2316
#抽一次删除一次
[root@localhost shellDemo]# wc -l phonenum.txt 
1000 phonenum.txt

4、批量创建用户(密码随机产生)

**需求:**批量创建5个用户,每个用户的密码为一个随机数

① 思路

  1. 循环5次创建用户
  2. 产生一个密码文件来保存用户的随机密码
  3. 从密码文件中取出随机密码赋值给用户

② 落地实现

#!/bin/env bash
#crate user and set passwd
#产生一个保存用户名和密码的文件
echo user0{1..5}:itcast$[$RANDOM%9000+1000]#@~|tr ' ' '\n'>> user_pass.file

#循环创建5个用户
for ((i=1;i<=5;i++))
do
	user=`head -$i user_pass.file|tail -1|cut -d: -f1`
	pass=`head -$i user_pass.file|tail -1|cut -d: -f2`
	useradd $user
	echo $pass|passwd --stdin $user
done

2 、嵌套循环

循环嵌套就是外层循环一次,内层循环一轮。

1、打印指定图案

#!/bin/env bash

for((i=1;i<=5;i++))
do
        for((x=1;x<=$i;x++))
        do
                #-n表示不换行输出
                echo -n $x
        done
#换行
echo
done

结果:
1
12
123
1234
12345

3、影响shell程序的内置命令

exit 退出整个程序
break 结束当前循环
continue 跳过本次循环
shift 使位置参数向左移动,默认移动一位,可以使用shift 2

举例说明:

以下脚本都能够实现用户自定义输入数字,然后脚本计算和:
[root@MissHou shell04]# cat shift.sh 
#!/bin/bash
sum=0
while [ $# -ne 0 ]
do
let sum=$sum+$1
#使位置参数向左移动 显示参数1,然后参数2下向左移动一位
shift
done
echo sum=$sum

./shift.sh  1 2 3
6

[root@MissHou shell04]# cat for3.sh 
#!/bin/bash
sum=0
# for循环的一种语法结构
for i
do
let sum=$sum+$i
done
echo sum=$sum

./for3.sh   1  2 3
6

4、expect

expect自动应答,tcl语言,是一门语言。

https://www.cnblogs.com/zhengbin/p/8872836.html

安装:yum -y install expect

例子1::远程登录到另一个服务器上什么都不做,exit退出

[root@localhost shellDemo]# cat expect.sh 
#!/usr/bin/env expect 

#开启一个程序,开启会话,接下来通过 expect ... send 来执行交互操作
spawn ssh root@192.168.169.128

#expect期望输出的字符串,send发送交互字符串,回车为 /n,注意空格
# 捕获相关内容 \r表示回车,exp_continue如果没有上一个,继续往下执行
expect {
        "(yes/no)?" { send "yes\r";exp_continue }
        "password:" { send "12345678\r" }
}
#交互
interact

使用位置参数:

#!/usr/bin/expect
set ip [ lindex $argv 0 ]
set pass [ lindex $argv 1 ]
set timeout 5
spawn ssh root@$ip
expect {
        "yes/no" { send "yes\r";exp_continue }
        "password:" { send "$pass\r" }
}
interact

执行脚本:
[root@localhost shellDemo]# ./expect.sh  192.168.169.128 12345678

例子2::远程登录到另一个服务器上做一些事情,exit退出

#!/usr/bin/expect
set ip [ lindex $argv 0 ]
set pass [ lindex $argv 1 ]
set timeout 5
spawn ssh root@$ip
expect {
        "yes/no" { send "yes\r";exp_continue }
        "password:" { send "$pass\r" }
}

#看到#号就做一些事
expect "#"
#删除目录里a,并回车
send "rm -rf /root/a\r"
#删除完目录,我还想看看主机名
send "hostname\r"
#再打一个日期看看
send "date +%F\r"
#结束程序,等待结束执行,若没有该结束符,脚本可能没有执行完毕就提前退出了
expect eof

执行脚本:
[root@localhost shellDemo]# ./expect.sh  192.168.169.128 12345678

例子3:shell脚本和expect结合使用,在多台服务器上创建1个用户

#!/bin/bash
# 循环在指定的服务器上创建用户和文件

#循环的从文件ip.txt中获取ip和密码
while read ip pass
do
        #/usr/bin/expect 脚本中首先引入解释文件,表明使用哪种 shell 解释器
        # <<-END表示遇到END,结束,这是shell的here文档,-表示END前面允许有制表符,这里不一定要写END,自定义的,一个字符而已
        #如果中途有一些输出全不要,丢到&>/dev/null中
        /usr/bin/expect <<-END
        #开启一个程序
        spawn ssh root@$ip
        expect {
        "(yes/no)?" { send "yes\r";exp_continue }
        "password:" { send "$pass\r" }
        }
        #期望看到#,如果看到就创建一个用户,删除一些东西,然后退出远程服务器
        expect "#" { send "useradd yy1;rm -rf /tmp/*;exit\r" }
        #结束程序
        expect eof
        END
echo "$ip服务器用户创建完毕!"
done < ip.txt

远程服务器查看用户是否创建成功

[root@localhost ~]# id yy1
uid=1001(yy1) gid=1001(yy1) 组=1001(yy1)

例子4:将跳板机上运维用户的公钥推送搭配局域网内可以ping通的所有机器上

跳板机,就是可以给你远程连接的机器,然后通过这个机器再去访问别的机器,

5、sudo简单介绍

给一个账号授予一些权限。

visudo
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
yunwei  ALL=(root)      NOPASSWD:ALL,!/sbin/shutdown,!/sbin/init,!/bin/rm -rf /

解释说明:
1)第一个字段yunwei指定的是用户:可以是用户名,也可以是别名。每个用户设置一行,多个用户设置多行,也可以将多个用户设置成一个别名后再进行设置。
2)第二个字段ALL指定的是用户所在的主机:可以是ip,也可以是主机名,表示该sudo设置只在该主机上生效,ALL表示在所有主机上都生效!限制的一般都是本机,也就是限制使用这个文件的主机;一般都指定为"ALL"表示所有的主机,不管文件拷到那里都可以用。比如:10.1.1.1=...则表示只在当前主机生效。
3)第三个字段(root)括号里指定的也是用户:指定以什么用户身份执行sudo,即使用sudo后可以享有所有root账号下的权限。如果要排除个别用户,可以在括号内设置,比如ALL=(ALL,!oracle,!pos)。
4)第四个字段ALL指定的是执行的命令:即使用sudo后可以执行所有的命令。除了关机和删除根内容以外;也可以设置别名。NOPASSWD: ALL表示使用sudo的不需要输入密码。
5)也可以授权给一个用户组
	%admin ALL=(ALL) ALL	表示admin组里的所有成员可以在任何主机上以任何用户身份执行任何命令

6、数组定义

数组分类:

  • 普通数组:只能使用整数作为数组索引
  • 关联索引:可以使用字符串作为数组索引

普通数组定义:

一次赋予一个值

数组名[索引下标]=值
array[0]=v0
array[1]=v1
array[2]=v2

一次赋予多个值:

数组名=(v1 v2 v3...)
names=(a b c d)
也可以是一个命令的输出
array1=(`cat 1.txt`)
array2=(`ls /root`)

查看普通数组:

获取指定的元素
[root@localhost shellDemo]# echo ${array1[3]}
world
获取所有元素
[root@localhost shellDemo]# echo ${array1[*]}
hello world hello world
获取数组长度
[root@localhost shellDemo]# echo ${#array1[*]}
4
获取数组元素的索引下标
[root@localhost shellDemo]# echo ${!array1[@]}
0 1 2 3
获取部分元素
[root@localhost shellDemo]# echo ${array1[*]:1:3}
world hello world
查看数组信息
[root@localhost shellDemo]# declare -a
declare -a BASH_ARGC='()'
declare -a BASH_ARGV='()'
declare -a BASH_LINENO='()'
declare -a BASH_SOURCE='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")'
declare -a DIRSTACK='()'
declare -a FUNCNAME='()'
declare -a GROUPS='()'
declare -a PIPESTATUS='([0]="0")'
declare -a array='([0]="harry" [1]="jack" [5]="jackaaa")'
declare -a array1='([0]="hello" [1]="world" [2]="hello" [3]="world")'
declare -a names='([0]="a" [1]="b" [2]="c" [3]="d")

关联数组定义:

[root@localhost shellDemo]# declare -A asso_array1
[root@localhost shellDemo]# asso_array1[linux]=1
[root@localhost shellDemo]# asso_array1[java]=2
[root@localhost shellDemo]# asso_array1=([php]=3 [python]=4 [go]=5)
[root@localhost shellDemo]# let asso_array1[linux]++

查看关联数组:

获取指定的元素
[root@localhost shellDemo]# echo ${asso_array1[go]}
5
打印数组的所有元素
[root@localhost shellDemo]# echo ${asso_array1[*]}
2 1
打印数组的索引
[root@localhost shellDemo]# echo ${!asso_array1[*]}
java linux
查看关联数组信息
[root@localhost shellDemo]# declare -A
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A asso_array1='([java]="2" [linux]="1" )'

使用例子:写一个脚本,统计web服务的不同链接状态个数

shell入门(五)

7、其他变量定义

变量内容的删出和替换:
shell入门(五)
去除一个目录下的目录和文件:
shell入门(五)

上一篇:expect 解决linux命令交互问题


下一篇:shell expect 拷贝文件夹有问题