Linux shell自动交互

  • 原创
  • Madman
  • /
  • 2018-04-24 09:50
  • /
  • 0
  • 409 次阅读

Linux Shell自动交互-min.png

Synopsis: shell脚本在处理自动循环或大的任务方面可节省大量的时间,通过创建一个处理任务的命令清单,使用变量、条件、算术和循环等方法快速创建脚本以完成相应工作,这比在命令行下一个个敲入命令要省时省力得多。有时候我们可能会需要实现和交互程序如fdisk、ftp、ssh、scp等进行交互的功能,这时候我们需要用到shell的自动交互功能。

1. 重定向

#!/bin/bash

fdisk /dev/sda << EOF
n
p
1
+10G
t
8e
w
EOF

2. 管道

#!/bin/bash

echo "n p 1 +10G t 8e w" | fdisk /dev/sda

普通用户修改自己的密码:

#!/bin/bash

passwd << EOF
旧密码
新密码
新密码
EOF

或者:

#!/bin/bash

(
  echo "旧密码"
  sleep 1
  echo "新密码"
  sleep 1
  echo "新密码"
) | passwd

如果是root用户执行脚本去修改普通用户的密码,可以使用--stdin选项:

#!/bin/bash

echo "新密码" | passwd --stdin 普通用户名

3. expect

expect是专门用于自动交互(automating interactive)的命令,功能强大,基于Tcl脚本语言,但CentOS中默认没有安装:

# rpm -qa | grep 'expect'
# yum -y install expect

3.1 使用介绍

expect详细使用方法请参考man except,它的常用指令如下:

(1) set

设置变量值

1. 设置expect永不超时
set timeout -1

2. 设置expect 300秒超时,如果超过300没有expect内容出现,则退出
set timeout 300

3. 获取命令行参数并赋值给变量,$argv 0对应命令行第一个参数,$argv 1对应命令行第二个参数,依次类推
set server [lindex $argv 0]
set user [lindex $argv 1] 
set password [lindex $argv 2]

(2) spawn

调用要执行的脚本或程序命令,如ssh、scp、ftp、telnet等

1. 执行当前目录下的脚本
spawn ./questions.sh

2. 启动ssh远程连接
spawn ssh -l $user $server 

(3) expect

等待spawn指定的脚本或命令的输出,即捕捉命令的提示信息,如果与expect后面的字符串匹配,就返回下面的send命令指定的响应字符串

命令的输出提示信息有可能会变化,所以可以在expect中使用模糊匹配,比如*

expect eof表示脚本结束

(4) send

向当前expect进程发送响应字符串,替代用户手动输入内容

(5) interact

将当前进程的控制权交还给用户,允许用户使用键盘等输入设备进行交互。比如,远程登录后,让用户后续可以操作远程终端。

假设当前目录下有一个询问用户一些问题的脚本:

# vim questions.sh

内容如下:
#!/bin/bash

echo "Hello, who are you?"
read $REPLY
echo "Can I ask you some questions?"
read $REPLY
echo "What is your favorite topic?"
read $REPLY

再创建一个自动应答的expect脚本:

# vim answerbot.exp

内容如下:
#!/usr/bin/expect -f

set timeout -1
spawn ./questions.sh
expect "Hello, who are you?\r"
send -- "Im Tom\r"
expect "Can I ask you some questions?\r"
send -- "Sure\r"
expect "What is your favorite topic?\r"
send -- "Technology\r"
expect eof

赋予两个脚本可执行权限,然后执行answerbot.exp:

[root@CentOS ~]# ./answerbot 
spawn ./questions
Hello, who are you?
Im Tom
Can I ask you some questions?
Sure
What is your favorite topic?
Technology

也可以使用autoexpect命令帮你生成自动应答脚本:

# autoexpect ./questions.sh

(6) 多分支

1. 单分支
expect "boy" { send "You are a boy." }

2. 多分支
expect "boy" { send "You are a boy." } \
expect "girl" { send "You are a girl." }

或者:
expect {
    "boy" { send "You are a boy." }
    "girl" { send "You are a girl." }
}

3. exp_continue表示匹配当前expect并send返回后,不结束进程,继续等待其它匹配
expect {
    "boy" { send "You are a boy."; exp_continue }
    "girl" { send "You are a girl."; exp_continue }
}

3.2 expect脚本

(1) ssh远程登录

1. 创建脚本autossh.exp
# vi autossh.exp

内容如下:
#!/usr/bin/expect -f

set timeout 5
set server [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]

spawn ssh -l $user $server 
expect {
    "*(yes/no)?" { send "yes\r"; exp_continue }
    "*password:" { send "$PASSWORD\r" }
}
expect "*Last login*"
interact 

2. 赋予可执行权限
# chmod +x autossh.exp

3. 执行脚本,node2主机远程登录到pxe主机
[root@node2 ~]# ./autossh.exp 172.17.40.31 root password
或者:
[root@node2 ~]# except autossh.exp 172.17.40.31 root password
spawn ssh -l root 172.17.40.31
The authenticity of host '172.17.40.31 (172.17.40.31)' can't be established.
RSA key fingerprint is 14:68:2d:0e:10:57:72:a3:ad:13:3d:ed:1d:78:7f:1d.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.17.40.31' (RSA) to the list of known hosts.
root@172.17.40.31's password: 
Last login: Thu Apr 21 06:36:54 2016 from 172.17.0.89
[root@pxe ~]# hostname
pxe
[root@pxe ~]# exit
logout
Connection to 172.17.40.31 closed.

(2) scp远程拷贝

1. autoscp创建脚本autoscp.exp
#!/usr/bin/expect -f

set timeout 10
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]

spawn scp $src_file $username@$host:$dest_file
expect {
    "*(yes/no)?" { send "yes\r"; exp_continue }
    "*password:" { send "$password\r" }
}
expect "100%"
expect eof

2. 赋予可执行权限
# chmod +x autoscp.exp

3. 执行脚本
[root@node2 ~]# expect autoscp.exp 172.17.40.31 root password /tmp/tcl-8.5.7-6.el6.x86_64.rpm /tmp
spawn scp /tmp/tcl-8.5.7-6.el6.x86_64.rpm root@172.17.40.31:/tmp
The authenticity of host '172.17.40.31 (172.17.40.31)' can't be established.
RSA key fingerprint is 14:68:2d:0e:10:57:72:a3:ad:13:3d:ed:1d:78:7f:1d.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.17.40.31' (RSA) to the list of known hosts.
root@172.17.40.31's password: 
tcl-8.5.7-6.el6.x86_64.rpm                                                                                                                                   100% 1961KB   1.9MB/s   00:00   

用途: 可以批量自动交互远程拷贝到多台机器上

#!/bin/bash
list_file=$1
src_file=$2
dest_file=$3

cat $list_file | while read line
do
   host_ip=`echo $line | awk '{print $1}'`
   username=`echo $line | awk '{print $2}'`
   password=`echo $line | awk '{print $3}'`

   echo "$host_ip"
   expect autoscp.exp $host_ip $username $password $src_file $dest_file
done

3.3 在shell脚本中使用expect命令

注意: 因为shell中也有set命令,所以expect不能设置变量,可以使用shell脚本内的变量

(1) 使用重定向

1. 创建shell脚本expect1.sh
#!/bin/bash

HOST='172.17.40.31'
PASSWORD='password'

/usr/bin/expect <<-EOF
spawn scp /tmp/tcl-8.5.7-6.el6.x86_64.rpm $HOST:/tmp
expect {
    "*(yes/no)?" { send "yes\r"; exp_continue }
    "*password:" { send "$PASSWORD\r" }
}
expect "100%"
expect eof
EOF

2. 执行
[root@node2 ~]# bash expect1.sh 
spawn scp /tmp/tcl-8.5.7-6.el6.x86_64.rpm 172.17.40.31:/tmp
The authenticity of host '172.17.40.31 (172.17.40.31)' can't be established.
RSA key fingerprint is 14:68:2d:0e:10:57:72:a3:ad:13:3d:ed:1d:78:7f:1d.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.17.40.31' (RSA) to the list of known hosts.
root@172.17.40.31's password: 
tcl-8.5.7-6.el6.x86_64.rpm                                                                                                                                   100% 1961KB   1.9MB/s   00:00    

(2) 使用-c选项

注意: -c后面的expect命令集合要用双引号引起来,因为里面有变量要解析,同时里面多余的双引号要用\转义

#!/bin/bash

HOST='172.17.40.31'
PASSWORD='password'

/usr/bin/expect -c "
    spawn scp /tmp/tcl-8.5.7-6.el6.x86_64.rpm $HOST:/tmp
    expect {
        \"*(yes/no)?\" { send \"yes\r\"; exp_continue }
        \"*password:\" { send \"$PASSWORD\r\" }
    }
    expect \"100%\"
    expect eof
"
未经允许不得转载: LIFE & SHARE - 王颜公子 » Linux shell自动交互

分享

作者

作者头像

Madman

如果博文内容有误或其它任何问题,欢迎留言评论,我会尽快回复; 或者通过QQ、微信等联系我

0 条评论

暂时还没有评论.

发表评论前请先登录