小脚本与expect的应用

编写脚本,接收两个位置参数,magedu和/www,判断系统是否有magedu,如果没有则自动创建magedu用户,并自动设置家目录为/www

[root@Centos7 scripts]# cat create_user.sh
#!/bin/bash
#

[ "$#" -eq 2 ]  || { echo "Please enter two parameters: magedu /www" ; exit 1 ;}

if [ "$1" == "magedu" -a "$2" == "/www" ] || [ "$1" == "/www" -a "$2" == "magedu" ]; then
    for i in $* ; do
        if [ "$i" == "magedu" ]; then
            USERNAME=$i
        else
            USERHOME=$i
        fi
    done
else
    echo "Parameter must be magedu and /www ..."
    exit 1
fi
if id ${USERNAME} &> /dev/null; then
    echo "${USERNAME} is existed..."
else
    useradd -d ${USERHOME} ${USERNAME}
    echo "${USERNAME} is created..."
fi

测试:

[root@Centos7 scripts]# ./create_user.sh 
Please enter two parameters: magedu /www

[root@Centos7 scripts]# ./create_user.sh www magedu
Parameter must be magedu and /www ...

[root@Centos7 scripts]# ./create_user.sh www magedu www
Please enter two parameters: magedu /www

[root@Centos7 scripts]# ./create_user.sh /www magedu 
magedu is created...
[root@Centos7 scripts]# ./create_user.sh /www magedu 
magedu is existed...
[root@Centos7 scripts]# getent passwd magedu
magedu:x:1001:1001::/www:/bin/bash

[root@Centos7 scripts]# ll /www -d
drwx------ 3 magedu magedu 78 8月  10 11:27 /www

expect
expect是由Don Libes基于Tcl(Tool Command Language)语言开发的,主要应用于自动化交互式操作的场景,借助expect处理交互式的命令,可以将交互过程如:ssh登陆,ftp登陆等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境,可以大大提高系统管理人员的工作效率

示例:ssh连接192.168.2.121
先观察当前主机ssh连接121有什么特征

[root@centos7 scripts]# ssh 192.168.2.121
[email protected]'s password:            #在ssh连接121时,需要输入密码,关键字是passwd    

使用脚本实现自动登录并且还停留在121上
注意:
1、脚本后缀名.exp (约定俗成的,并非一定)
2、脚本开头是/usr/bin/expect (通过which expect查看路径)

[root@centos7 scripts]# which expect
/usr/bin/expect
[root@centos7 scripts]# vim expect_ssh.exp
[root@centos7 scripts]# cat expect_ssh.exp
#!/usr/bin/expect
#
set timeout 30
set host "192.168.2.121"
set username "root"
set password "123.com"

spawn ssh $username@$host
expect "password" {send "$password\r"}     #\r是回车
#interact                                  #当注释interact时,是不会停留在121机器上的  

[root@centos7 scripts]# chmod +x expect_ssh.exp
[root@centos7 scripts]# ./expect_ssh.exp
spawn ssh [email protected]
[email protected]'s password: [root@centos7 scripts]#        #直接返回到了测试机器终端上

[root@centos7 scripts]# vim expect_ssh.exp
[root@centos7 scripts]# cat expect_ssh.exp
#!/usr/bin/expect
#
set timeout 30                    #设置超时时长,单位为秒,默认是10秒
set host "192.168.2.121"          #设置变量host
set username "root"               #设置变量username
set password "123.com"            #设置变量password

spawn ssh $username@$host         #spawn是进入expect环境后才才可以执行expect内部命令,如果没有装expect或直接在默认的shell下执行是找不到spawn命令的,主要功能就是给ssh运行进程加个壳,用来传递交互指令
expect "password" {send "$password\r"}
interact                          #开启interact,对比下效果;执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上

[root@centos7 scripts]# ./expect_ssh.exp
spawn ssh [email protected]
[email protected]'s password:
Last login: Sun Jun 21 13:48:37 2020 from centos7.lan
[root@Centos6 ~]#                 #这台centos6的机器就是192.168.2.121

这就是对上述这段简单简单脚本的分析,在上述的示例中,涉及到expect中一个非常重要的概念——模式-动作;即上述expect "password" {send "$password\r"}这句代码表达出来的含义

刚那是已经有连接过121机器,所以会跳过指纹验证那块,接下来再来,把known_hosts删除,模拟一个全新的ssh连接。注意观察特征

[root@centos7 scripts]# rm ~root/.ssh/known_hosts
rm: remove regular file ‘/root/.ssh/known_hosts’? y

[root@centos7 scripts]# ssh 192.168.2.121                #蓝色表示特征,也就是需要匹配的值,粉红是需要手动输入的,当然password哪里也是需要输入手动密码
The authenticity of host '192.168.2.121 (192.168.2.121)' can't be established.
RSA key fingerprint is SHA256:oOQ2p3kF0ksYSimQxOywI9zkxFOx0JARw5aIkfO/eqQ.
RSA key fingerprint is MD5:6c:d9:39:01:d9:a5:16:68:b1:1e:c1:5f:7f:b5:fa:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.121' (RSA) to the list of known hosts.
[email protected]'s password:
[root@centos7 scripts]# !rm
rm ~root/.ssh/known_hosts
rm: remove regular file ‘/root/.ssh/known_hosts’? y

[root@centos7 scripts]# vim expect_ssh2.exp
[root@centos7 scripts]# cat expect_ssh2.exp
#!/usr/bin/expect
#
set timeout 30
set host "192.168.2.121"
set username "root"
set password "123.com"

spawn ssh $username@$host
expect {
    "yes/no" {send "yes\r"}
    "password" {send "$password\r"}
}
interact

[root@centos7 scripts]# ./expect_ssh2.exp
spawn ssh [email protected]
The authenticity of host '192.168.2.121 (192.168.2.121)' can't be established.
RSA key fingerprint is SHA256:oOQ2p3kF0ksYSimQxOywI9zkxFOx0JARw5aIkfO/eqQ.
RSA key fingerprint is MD5:6c:d9:39:01:d9:a5:16:68:b1:1e:c1:5f:7f:b5:fa:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.121' (RSA) to the list of known hosts.
[email protected]'s password:                #停留在这里不动了,需要手动输入密码才行

#解决方法:增加exp_continue
[root@centos7 scripts]# vim expect_ssh2.exp
[root@centos7 scripts]# cat expect_ssh2.exp
#!/usr/bin/expect
#
set timeout 30
set host "192.168.2.121"
set username "root"
set password "123.com"

spawn ssh $username@$host
expect {
    "yes/no" {send "yes\r"; exp_continue}   #类似于while循环里的continue,当匹配到yes/no后,再次进行下次匹配,password,如果还有其它的匹配,那么需要增加exp_continue到倒数第二个匹配里
    "password" {send "$password\r"}
}
interact

[root@centos7 scripts]# ./expect_ssh2.exp
spawn ssh [email protected]
The authenticity of host '192.168.2.121 (192.168.2.121)' can't be established.
RSA key fingerprint is SHA256:oOQ2p3kF0ksYSimQxOywI9zkxFOx0JARw5aIkfO/eqQ.
RSA key fingerprint is MD5:6c:d9:39:01:d9:a5:16:68:b1:1e:c1:5f:7f:b5:fa:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.121' (RSA) to the list of known hosts.
[email protected]'s password:
Last login: Sun Jun 21 14:23:29 2020 from centos7.lan
[root@Centos6 ~]# ls
anaconda-ks.cfg  install.log  install.log.syslog

[root@centos7 scripts]# vim expect_ssh2.exp
[root@centos7 scripts]# cat expect_ssh2.exp
#!/usr/bin/expect
#
set timeout 30
set host "192.168.2.121"
set username "root"
set password "123.com"

spawn ssh $username@$host
expect {
    "yes/no" {send "yes\r"; exp_continue}
    "password" {send "$password\r"}
}
expect eof                #等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了
#interact

[root@centos7 scripts]# ./expect_ssh2.exp
spawn ssh [email protected]
The authenticity of host '192.168.2.121 (192.168.2.121)' can't be established.
RSA key fingerprint is SHA256:oOQ2p3kF0ksYSimQxOywI9zkxFOx0JARw5aIkfO/eqQ.
RSA key fingerprint is MD5:6c:d9:39:01:d9:a5:16:68:b1:1e:c1:5f:7f:b5:fa:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.121' (RSA) to the list of known hosts.
[email protected]'s password:
Last login: Sun Jun 21 14:38:17 2020 from centos7.lan
[root@Centos6 ~]# ls            #光标卡住不懂了,一直等待超时30秒,然后回到centos7,并且还执行了ls命令
[root@centos7 scripts]# ls
1.txt                disk.sh                ip2.sh         outputKS.sh       select7.sh         trap_test.sh
2.txt                d.txt                  ipaddr.sh      pre.sh            select8.sh         user2.sh
99_2.sh              dysjx.sh               ip.sh          print_action2.sh  service_state2.sh  useradd-1.sh
99.sh                excute.sh              links.sh       print_action.sh   service_state.sh   useradd.sh
argsnum2.sh          expect_ssh2.exp  

expect eof:等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了
interact:执行完成后保持交互状态, 这时可以手动输入信息
注意:expect eof与interact二选一即可

接收参数
expect参数存在argv中,具体示例说明

[root@centos7 scripts]# vim expect_ssh3.exp
[root@centos7 scripts]# cat expect_ssh3.exp
#!/usr/bin/expect
#
set timeout 30
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]

if { $argc < 3} {     #注意}{这两个之间是有空格的,而且在expect里,if条件时用大括号而非bash []或者其他语言的();$argc就是参数个数,相当于$#,可以如此记忆,arg是参数,后面的c表示count,个数的意思;$argv,后面的v表示value,值得意思
#     puts "Usage:argv0 <host> <username> <password>\n"        #puts和send_user相同功能,类似bash shell中的echo -e
     send_user "Usage:$argv0 <host> <username> <password>\n"   #$argv0是脚本名,但是[lindex $argv 0]是第一个参数,[lindex $argv 1]是第二个参数,依次类推;$argv0相当于bash位置变量的$0,[lindex $argv 1]相当于$1
     exit
}

spawn ssh $username@$host
expect {
    "yes/no" {send "yes\r"; exp_continue}
    "password" {send "$password\r"}
}
interact

[root@centos7 scripts]# ./expect_ssh3.exp 192.168.2.121 root 123.com
spawn ssh [email protected]
The authenticity of host '192.168.2.121 (192.168.2.121)' can't be established.
RSA key fingerprint is SHA256:oOQ2p3kF0ksYSimQxOywI9zkxFOx0JARw5aIkfO/eqQ.
RSA key fingerprint is MD5:6c:d9:39:01:d9:a5:16:68:b1:1e:c1:5f:7f:b5:fa:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.121' (RSA) to the list of known hosts.
[email protected]'s password:
Last login: Sun Jun 21 14:46:25 2020 from centos7.lan
[root@Centos6 ~]# ls
anaconda-ks.cfg  install.log  install.log.syslog

执行多个命令
结尾就不需要使用interact,而使用expect eof,毕竟不需要停留在对方终端上
这里通过“]#”来做匹配;创建kyle用户

[root@Centos6 ~]# getent passwd kyle
[root@Centos6 ~]#

[root@centos7 scripts]# vim expect_ssh4.exp
[root@centos7 scripts]# cat expect_ssh4.exp
#!/usr/bin/expect
#
set timeout 30
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]

if { $argc < 3} {
#   puts "Usage:argv0 <host> <username> <password>\n"
    send_user "Usage:$argv0 <host> <username> <password>\n"
    exit
}

spawn ssh $username@$host
expect {
    "yes/no" {send "yes\r"; exp_continue}
    "password" {send "$password\r"}
}
expect "]#" {send "useradd kyle\r"}
expect "]#" {send "echo 123.com | passwd --stdin kyle\r"}
expect eof

[root@centos7 scripts]# ./expect_ssh4.exp 192.168.2.121 root 123.com
spawn ssh [email protected]
The authenticity of host '192.168.2.121 (192.168.2.121)' can't be established.
RSA key fingerprint is SHA256:oOQ2p3kF0ksYSimQxOywI9zkxFOx0JARw5aIkfO/eqQ.
RSA key fingerprint is MD5:6c:d9:39:01:d9:a5:16:68:b1:1e:c1:5f:7f:b5:fa:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.121' (RSA) to the list of known hosts.
[email protected]'s password:
Last login: Sun Jun 21 14:46:33 2020 from centos7.lan
[root@Centos6 ~]# useradd kyle
[root@Centos6 ~]# echo 123.com | passwd --stdin kyle
Changing password for user kyle.
passwd: all authentication tokens updated successfully.

#切换到121机器上查看,因为之前写的脚本结束是expect eof,所以不能直接在121上操作。xshell连接到121上查看用户是否已经创建,其实上面红色标记已经显示很清楚已经创建了
[root@Centos6 ~]# getent passwd kyle            #已经创建kyle用户,并且已经设置了密码
kyle:x:500:500::/home/kyle:/bin/bash
[root@Centos6 ~]# getent shadow kyle
kyle:$6$S.NY9Bt0$R2sVfsh7G3gLgviVt/cTZxWhoLRIfeJ.slX.j3z2OOS8kANN6g1YU6j.Wc3U6rX20kn70TjayN5jrgw3LfAeK.:18434:0:99999:7:::

shell脚本调用expect
同样是上面脚本的改进,这次是增加kevin这个用户,并设置密码,同时也解决之前,执行完脚本后会停留在121终端上的问题

[root@Centos6 ~]# getent passwd kevin
[root@Centos6 ~]#

[root@centos7 scripts]# vim expect_ssh5.sh
[root@centos7 scripts]# cat expect_ssh5.sh
#!/bin/bash
#
host=$1
username=$2
password=$3

if [ "$#" -lt 3 ];then              #与之前expect编写参数用法对照看
    echo  "Usage:$0 <host> <username> <password>"
    exit
fi

expect << EOF
spawn ssh $username@$host
expect {                            #注意,在shell调用expect脚本中大括号都需要空格,不像之前直接expect那样,不需要空格
    "yes/no" { send "yes\r"; exp_continue }
    "password" { send "$password\r" }
}
expect "]#" { send "useradd kevin\r" }
expect "]#" { send "echo 123.com | passwd --stdin kevin\r" }
expect "]#" { send "exit\r" }       #增加这条expect后,就不需要再停留在121机器上了
expect eof
EOF

[root@centos7 scripts]# ./expect_ssh5.sh 192.168.2.121 root            #能判断参数
Usage:./expect_ssh5.sh <host> <username> <password>

[root@centos7 scripts]# ./expect_ssh5.sh 192.168.2.121 root 123.com    #完全自动化操作,非人工输入
spawn ssh [email protected]
[email protected]'s password:
Last login: Sun Jun 21 15:26:47 2020 from centos7.lan
[root@Centos6 ~]# useradd kevin
[root@Centos6 ~]# echo 123.com | passwd --stdin kevin
Changing password for user kevin.
passwd: all authentication tokens updated successfully.
[root@Centos6 ~]# exit
logout
Connection to 192.168.2.121 closed.
[root@centos7 scripts]#

#验证结果如下
[root@Centos6 ~]# getent passwd kevin
kevin:x:502:502::/home/kevin:/bin/bash
[root@Centos6 ~]# getent shadow kevin
kevin:$6$iL5UNV/1$0ofohxfg8qUIM1Cxf8swxBqaZ2yyTVVdcw8.ynUNVe5Nhj/Dg3DDxTRWuEDnQd5IQ.Xyf.xHQQcdKC3eNCGeV1:18434:0:99999:7:::

猜你喜欢

转载自blog.51cto.com/14812296/2518570