当前位置: 首页 > news >正文

shell 中 expect 详解

一、概述

     Expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。Expect的作者DonLibes在1990年开始编写Expect时对Expect做有如下定义:Expect是一个用来实现自动交互功能的软件套件。通过expect系统管理员可以创建脚本用来实现对命令或程序提供输入,而这些命令和程序是期望从终端(terminal)得到输入,一般来说这些输入都需要手工输入进行的。Expect则可以根据程序的提示模拟标准输入提供给程序需要的输入来实现交互程序执行。甚至可以实现实现简单的BBS聊天机器人。

我们通过Shell可以实现简单的控制流功能,如:循环、判断等。但是对于需要交互的场合则必须通过人工来干预,有时候我们可能会需要实现与SSH、FTP服务器等进行免交互的自动连接功能,而Expect正是用来实现这种功能的工具。

Expect是不断发展的,随着时间的流逝,其功能越来越强大,已经成为系统管理员的的一个强大助手。Expect需要Tcl编程语言的支持,所以要在系统上运行Expect必须首先安装Tcl。

通过ssh远程操控主机时交互解决方式:

  1. 通过ssh的密钥对

  2. 通过sshpass工具提交密码

  3. 通过expect工具提交密码

二、安装expect

[root@localhost ~]# rpm -q expect
​
[root@localhost ~]# yum -y install expect

三、如何使用expect

在使用expect程序前,我们首先简单说下expect在常规使用中的工作流程:

首先expect的内部命令spawn启动指定进程-->expect获取期待的关键字-->内部命令send向指定进程发送响应内容-->进程执行完成后,退出expect程序。

通过上面expect的工作流程,我们可以认识到,expect的内置命令:spawn、expect、send等非常重要,所以下面我们先来了解下它们的使用。

3-1、spawn命令

spawn作用:启动新的产生交互的进程

spawn命令的语法:

spawn [选项] [需要执行的shell命令或程序等]

下面我们以修改一个已存在账户的密码为例,举例如下:

[root@localhost ~]# useradd tom
​
[root@localhost ~]# passwd tom
​
更改用户 tom 的密码 。
​
新的 密码:
​
无效的密码: 密码未通过字典检查 - 过于简单化/系统化
​
重新输入新的 密码:
​
passwd:所有的身份验证令牌已经成功更新。

基于expect交互界面做法

[root@localhost ~]# expect
​
expect1.1> spawn passwd tom
​
spawn passwd tom
​
1388
​
expect1.2> expect "密码:"
​
更改用户 tom 的密码 。
​
新的 密码:expect1.3> send "123456\r"
​
expect1.4> expect "密码:"
​
无效的密码: 密码少于 8 个字符
​
重新输入新的 密码:expect1.5> send "123456\r"
​
expect1.6> expect eof
​
passwd:所有的身份验证令牌已经成功更新。
​
expect1.7> exit

3-2、expect命令

expect作用:获取从spawn命令执行的命令和程序后产生的交互信息。看看是否匹配,如果匹配,就开始执行expect进程接收字符串。

expect命令的语法:

  expect [选项] 表达式 [动作]

  选项:比如"-re"表示使用正则表达式来进行匹配。

案例:

[root@localhost ~]# expect
​
expect1.1> spawn passwd tom
​
spawn passwd tom
​
1437
​
expect1.2> expect "新的 密码:"
​
更改用户 tom 的密码 。
​
新的 密码:expect1.3> send "123456\r"
​
expect1.4> expect "新的 密码:"
​
无效的密码: 密码少于 8 个字符
​
重新输入新的 密码:expect1.5> send "123456\r"
​
expect1.6> expect eof
​
passwd:所有的身份验证令牌已经成功更新。
​
expect1.7> exit

3-3、send命令

send命令的主要作用是,在expect命令匹配完指定的字符后,发送指定的字符串给系统程序,在字符中可以支持部分特殊转义符,比如:n(回车)r(换行)t(制表符)等。

案例:

[root@localhost ~]# expect
​
expect1.1> spawn passwd tom
​
spawn passwd tom
​
1437
​
expect1.2> expect "新的 密码:"
​
更改用户 tom 的密码 。
​
新的 密码:expect1.3> send "123456\r"
​
expect1.4> expect "新的 密码:"
​
无效的密码: 密码少于 8 个字符
​
重新输入新的 密码:expect1.5> send "123456\r"
​
expect1.6> expect eof
​
passwd:所有的身份验证令牌已经成功更新。
​
expect1.7> exit

下面是上述实验的expect脚本案例:

修改密码案例1:

[root@localhost ~]# vim change_pass1.exp
​
#!/usr/bin/expect
​
# Filename : change_pass1.exp
​
spawn passwd tom
​
expect "密码:"
​
send "123456\r"
​
expect "新的 密码:"
​
send "123456\r"
​
expect eof
​
[root@localhost ~]# chmod +x change_pass1.exp
​
[root@localhost ~]# ./change_pass1.exp
​
spawn passwd tom
​
更改用户 tom 的密码 。
​
新的 密码:
​
无效的密码: 密码少于 8 个字符
​
重新输入新的 密码:
​
passwd:所有的身份验证令牌已经成功更新。

修改密码案例2:

[root@localhost ~]# vim chang_pass2.exp
​
#!/usr/bin/expect
​
# Filename : change_pass2.exp
​
spawn passwd tom
​
expect {
​
"新的 密码:" { send "123456\r"; exp_continue }
​
"新的 密码:" { send "123456\r" }
​
eof
​
}
​
[root@localhost ~]# chmod +x chang_pass2.exp
​
[root@localhost ~]# ./chang_pass2.exp
​
spawn passwd tom
​
更改用户 tom 的密码 。
​
新的 密码:
​
无效的密码: 密码少于 8 个字符
​
重新输入新的 密码:
​
passwd:所有的身份验证令牌已经成功更新。

3-4、exp_continue命令

exp_continue命令的主要作用是,如果需要一次匹配多个字符串,那么多次匹配字符串并执行不同的动作中,可以让expect程序实现继续匹配的效果。

案例:

[root@localhost ~]# vim chang_pass2.exp
​
#!/usr/bin/expect
​
# Filename : change_pass2.exp
​
spawn passwd tom
​
expect {
​
"新的 密码:" { send "123456\r"; exp_continue }
​
"新的 密码:" { send "123456\r" }
​
eof
​
}
​
[root@localhost ~]# chmod +x chang_pass2.exp
​
[root@localhost ~]# ./chang_pass2.exp
​
spawn passwd tom
​
更改用户 tom 的密码 。
​
新的 密码:
​
无效的密码: 密码少于 8 个字符
​
重新输入新的 密码:
​
passwd:所有的身份验证令牌已经成功更新。

3-5、send_user命令

send_user命令的作用是:用来打印expect脚本信息,类似shell里的echo命令。

[root@localhost ~]# vim send_user.exp
​
#!/usr/bin/expect
​
#Filename: send_user.exp
​
send_user "beijingn"
​
send_user "shanghait"
​
send_user "guangzhoun"
​
[root@localhost ~]# chmod +x send_user.exp
​
[root@localhost ~]# ./send_user.exp
​
beijing
​
shanghai guangzhou

3-6、expect变量

3-6-1、普通变量

expect中定义普通变量的语法如下:

set 变量名 变量值

例如:

set chengshi "beijing"

调取变量的方法是:

puts $变量名
​
#或者
​
send_user "$变量名"

案例:

[root@localhost ~]# vim expect_var.exp
​
#!/usr/bin/expect
​
# Filename: expect_var.exp
​
set name "crushlinux"
​
set address "beijing"
​
puts $name
​
send_user "$name t $addressn"
​
[root@localhost ~]# chmod +x expect_var.exp
​
[root@localhost ~]# ./expect_var.exp
​
crushlinux
​
crushlinux beijing

3-6-2、expect中位置参数变量

如何向expect脚本中像shell一样传递类似于$0、$1等位置参数,用于接收及控制expect脚本传递位置参数变量呢?

expect是通过如下语法来进行的:

set <变量名称> [lindex $argv <param index> ]

当然,除了基本的位置参数外,expect还支持其它的特殊参数,比如:

$argc 表示传入参数的个数

$argv0 表示当前执行脚本的名称。

案例:

[root@localhost ~]# vim expect_var2.exp
​
#!/usr/bin/expect
​
# Filename: expect_var2.exp
​
set file1 [lindex $argv 0]
​
set file2 [lindex $argv 1]
​
set file3 [lindex $argv 2]
​
puts "The files are : $file1 $file2 $file3"
​
puts "The number of files are: $argc"
​
puts "The expect script name is: $argv0"
​
[root@localhost ~]# chmod +x expect_var2.exp
​
[root@localhost ~]# ./expect_var2.exp 1.txt 2.txt 3.txt
​
The files are : 1.txt 2.txt 3.txt
​
The number of files are: 3
​
The expect script name is: ./expect_var2.exp

3-7、expect中if条件语句

expect中if 条件语句的语法结构如下:

if {条件表达式} {
​
commands;
​
}
​
if {条件表达式} {
​
commands;
​
} else {
​
commands;
​
}

注意事项:上面条件语句中每个"{"前要至少保证有一个空格。

案例:

[root@localhost ~]# vim expect-if.exp
​
#!/usr/bin/expect
​
# Filename: expect-if.exp
​
if {$argc <= 3} {
​
puts "The IP numbers <= 3"
​
} else {
​
puts "The IP numbers > 3"
​
}
​
[root@localhost ~]# chmod +x expect-if.sh
​
[root@localhost ~]# ./expect-if.sh 192.168.200.{1..3}
​
The IP numbers <= 3
​
[root@localhost ~]# ./expect-if.sh 192.168.200.{1..5}
​
The IP numbers > 3

3-8、expect中常用关键字

3-8-1 eof关键字

eof是和spawn对应的,当spawn发送指令到终端执行起始会有一个eof,等指令在终端完毕后,在返回时eof被expect捕捉,就好比在shell中cat >>file <<OEFrr content rrEOF一样,在结束时也要有EOF,这样是对应的。因前面案例中已有举例,这里就不再举例说明。

Interact允许用户交互,由管理员结束进程。

3-8-2 timeout关键字

expect脚本我们都知道,首先spawn我们要执行的命令,然后就给出一堆expect的屏幕输出,如果输出匹配了我们的expect的正则匹配内容,我们就会send一个命令上去,模拟用户输入。

但是expect中等待命令的输出信息是有一个timeout的设定的,默认是10秒。这个特性是防止那些执行死机的命令的。一旦到了这个timeout,还是没有屏幕输出的话,expect脚本中下面的代码就会执行。或者我们在expect脚本中如果定义了timeout的响应代码的话,这些代码就会被执行。

解决这样的问题非常简单,最简单的办法就是在expect脚本的开头定义:

set timeout -1 -- 永久不超时
​
set timeout 0 -- 立即执行
​
set timeout XX -- 设定具体的timeout时间(秒),默认是10秒。

案例1:

[root@localhost ~]# vim expect-timeout.exp
​
#!/usr/bin/expect
​
# Filename: expect-timeout.exp
​
spawn ssh root@192.168.200.112 ifconfig ens32
​
set timeout 15
​
expect {
​
"yes/no" { send "yesn"; exp_continue }
​
timeout { puts "request timeout 15s r" }
​
}
​
[root@localhost ~]# chmod +x expect-timeout.exp
​
[root@localhost ~]# ./expect-timeout.exp
​
spawn ssh root@192.168.200.112 ifconfig ens32
​
root@192.168.200.112's password: request timeout 15s
<--此处等待15秒后显示。

案例2:

[root@localhost ~]# vim expect-timeout2.exp
​
#!/usr/bin/expect
​
# Filename: expect-timeout2.exp
​
spawn ssh root@192.168.200.112 ifconfig ens32
​
set timeout 15
​
expect {
​
"yes/no" { send "yesn"; exp_continue }
​
"*password*" { send "123456\r" }
​
}
​
expect eof
​
#interact
​
[root@localhost ~]# chmod +x expect-timeout.exp
​
[root@localhost ~]# ./expect-timeout.exp
​
spawn ssh root@192.168.200.112 ifconfig ens32
​
root@192.168.200.112's password:
​
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
​
inet 192.168.200.112 netmask 255.255.255.0 broadcast 192.168.200.255
​
inet6 fe80::20c:29ff:fe8c:f2d9 prefixlen 64 scopeid 0x20<link>
​
ether 00:0c:29:8c:f2:d9 txqueuelen 1000 (Ethernet)
​
RX packets 2472 bytes 1511193 (1.4 MiB)
​
RX errors 0 dropped 0 overruns 0 frame 0
​
TX packets 1714 bytes 211891 (206.9 KiB)
​
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

在上面的这个案例中没有等待15秒才输出结果,是因为中间没有屏幕输出需要交互等待15秒钟的动作。

3-9、expect中for循环语句

{ set i 1 } 定义i的值为1
​
{ $i <= 10 }循环的条件
​
{ incr i 1} 制定$i的增量值,必须写在这行的末尾处,默认增量值为1
[root@localhost ~]# cat expect-for.exp
​
#!/usr/bin/expect
​
for { set i 1 } { $i <= 10 } { incr i 1 } {
​
puts "$i"
​
}
​
[root@localhost ~]# expect expect-for.exp
​
1
​
2
​
3
​
4
​
5
​
6
​
7
​
8
​
9
​
10

3-10、expect中while循环语句

[root@localhost ~]# vim expect-while.exp
​
#!/usr/bin/expect
​
set i 1
​
while {$i <= 10} {
​
puts "$i"
​
sleep 1
​
incr i 1
​
}[root@localhost ~]# expect expect-while.exp
​
1
​
2
​
3
​
4
​
5
​
6
​
7
​
8
​
9
​
10

四、Shell脚本调用expect 的方法

  1. 在shell脚本中使用expect --c "..."可以在shell中调用expect编程语言;

[root@localhost ~]# cat shell-expect1.sh
​
#!/bin/bash
​
for i in 192.168.200.{112..113}
​
do
​
expect -c "
​
spawn ssh root@$i ifconfig ens32
​
expect {
​
"yes/no" { send "yes\r";exp_continue }
​
"password" { send "123456\n" }
​
}
​
expect eof
​
"
​
done
​
[root@localhost ~]# bash shell-expect1.sh
​
spawn ssh root@192.168.200.112 ifconfig ens32
​
root@192.168.200.112's password:
​
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
​
inet 192.168.200.112 netmask 255.255.255.0 broadcast 192.168.200.255
​
inet6 fe80::20c:29ff:fe8c:f2d9 prefixlen 64 scopeid 0x20<link>
​
ether 00:0c:29:8c:f2:d9 txqueuelen 1000 (Ethernet)
​
RX packets 3512 bytes 1656192 (1.5 MiB)
​
RX errors 0 dropped 0 overruns 0 frame 0
​
TX packets 2808 bytes 365154 (356.5 KiB)
​
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
​
spawn ssh root@192.168.200.113 ifconfig ens32
​
root@192.168.200.113's password:
​
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
​
inet 192.168.200.113 netmask 255.255.255.0 broadcast 192.168.200.255
​
inet6 fe80::20c:29ff:fe0b:7eab prefixlen 64 scopeid 0x20<link>
​
ether 00:0c:29:0b:7e:ab txqueuelen 1000 (Ethernet)
​
RX packets 2722 bytes 1511052 (1.4 MiB)
​
RX errors 0 dropped 0 overruns 0 frame 0
​
TX packets 2196 bytes 258197 (252.1 KiB)
​
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

2.在shell脚本中使用/usr/bin/expect <<-EOF ...EOF的方式可以调用绝大多数的其它脚本语言,这种方式执行命令建议使用绝对路径,而且要严格遵守expect的脚本格式;

[root@localhost ~]# cat shell-expect2.sh
​
#!/bin/bash
​
for i in 192.168.200.{112..113}
​
do
​
/usr/bin/expect << EOF
​
spawn ssh root@$i ifconfig ens32
​
expect {
​
"yes/no" { send "yes\r";exp_continue }
​
"password" { send "123456\n" }
​
}
​
expect eof
​
EOF
​
done
​
[root@localhost ~]# bash shell-expect2.sh
​
spawn ssh root@192.168.200.112 ifconfig ens32
​
root@192.168.200.112's password:
​
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
​
inet 192.168.200.112 netmask 255.255.255.0 broadcast 192.168.200.255
​
inet6 fe80::20c:29ff:fe8c:f2d9 prefixlen 64 scopeid 0x20<link>
​
ether 00:0c:29:8c:f2:d9 txqueuelen 1000 (Ethernet)
​
RX packets 3329 bytes 1632688 (1.5 MiB)
​
RX errors 0 dropped 0 overruns 0 frame 0
​
TX packets 2609 bytes 340022 (332.0 KiB)
​
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
​
spawn ssh root@192.168.200.113 ifconfig ens32
​
root@192.168.200.113's password:
​
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
​
inet 192.168.200.113 netmask 255.255.255.0 broadcast 192.168.200.255
​
inet6 fe80::20c:29ff:fe0b:7eab prefixlen 64 scopeid 0x20<link>
​
ether 00:0c:29:0b:7e:ab txqueuelen 1000 (Ethernet)
​
RX packets 2561 bytes 1488208 (1.4 MiB)
​
RX errors 0 dropped 0 overruns 0 frame 0
​
TX packets 1997 bytes 233005 (227.5 KiB)
​
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
​
[root@localhost ~]# cat zhixing.sh
​
#!/bin/bash
​
for i in 192.168.200.{112..113}
​
do
​
/usr/bin/expect << EOF
​
spawn ssh root@$i wget http://192.168.200.111/user20.sh -O
/tmp/user20.sh && bash /tmp/user20.sh
​
expect {
​
"yes/no" { send "yesr";exp_continue }
​
"password" { send "123456n" }
​
}
​
expect eof
​
EOF
​
done

五、expect在生产环境中的案例

案例要求:

手边现在有一个统计CPU信息的脚本(cpuinfo.sh),该脚本在单独的物理服务器上或虚拟主机上执行后,能统计该机器CPU的五个相关信息,比如:

[root@localhost ~]# sh cpuinfo.sh
​
logical CPU number in total: 32 //当前机器中逻辑CPU个数为:32
​
phycical CPU number in total: 2 //当前机器中物理CPU颗数为: 2
​
core number in a physical CPU: 8 //机器中每颗物理CPU有8核心
​
logical CPU number in a phycical CPU:16 //机器中每颗物理CPU 有16
个逻辑CPU
​
Hyper threading is enabled. //每颗CPU的超线程已经打开

具体代码如下:

[root@localhost ~]# cat cpuinfo.sh
​
#!/bin/bash
​
# filename: cpu-info.sh
​
#this script only works in a Linux system which has one or more
indentical physical CPU(S)
​
echo -n "logical CPU number in total: "
​
#逻辑CPU个数
​
cat /proc/cpuinfo |grep "^processor" |wc -l
​
#有些系统没有多核也没有打开超线程,就直接退出脚本
​
cat /proc/cpuinfo |grep -qi "core id"
​
if [ $? -ne 0 ]; then
​
echo "Warning. No multi-core or hyper-threading is enabled."
​
exit 0;
​
fi
​
echo -n "phycical CPU number in total: "
​
#物理CPU个数
​
cat /proc/cpuinfo |grep "physical id" |sort |uniq |wc -l
​
echo -n "core number in a physical CPU: "
​
#每个物理CPU上的core的个数(未计入超线程)
​
core_per_phy_cpu=$(cat /proc/cpuinfo |grep "core id"|sort |uniq
|wc -l)
​
echo $core_per_phy_cpu
​
echo -n "logical CPU number in a phycical CPU:"
​
#每个物理CPU中逻辑CPU(可能是core,threads或both)的个数
​
logical_cpu_per_phy_cpu=$(cat /proc/cpuinfo |grep "siblings"|sort
|uniq |awk -F: '{print $2}')
​
echo $logical_cpu_per_phy_cpu
​
#是否打开有超线程
​
#如果在同一个物理CPU上有两个逻辑CPU具有相同的"core
id",那么超线程是打开的
​
#此处根据前面计算的 core_per_phy_cpu和
logical_cpu_per_phy_cpu的比较来查看超线程
​
if [ $logical_cpu_per_phy_cpu -gt $core_per_phy_cpu ]; then
​
echo "Hyper threading is enabled."
​
elif [ $logical_cpu_per_phy_cpu -eq $core_per_phy_cpu ]; then
​
echo "Hyper threading is NOT enabled."
​
else
​
echo "Error. There's something wrong."
​
fi

下面我们要做的是将这个脚本通过expect批量分发到指定范围的机器上进行自动化跑批量,以便能通过shell脚本自动统计批量采集所有被指定机器上的CPU相关信息。具体脚本实现思路如下:

1)通过expect实现将单一脚本自动免交互上传至指定客户机。

2)通过shell脚本中的循环语句,调取expect单机自动免交互上传文件脚本。从而实现将cpuinfo.sh脚本批量上传到客户机指定目录下。

3)通过expect实现自动免交互方式在指定单台客户机上执行指定命令或脚本程序。

4)通过shell脚本中的循环语句,调取单机免交互自动执行脚本程序的expect脚本。从而实现在多台机器上免交互自动执行shell脚本。

脚本案例如下:

1)通过expect实现将单一脚本自动免交互上传至指定客户机。

[root@localhost ~]# vim auto_upload_file.exp
​
#!/usr/bin/expect
​
# Filename: auto_upload_file.exp
​
if { $argc != 3 } {
​
puts "usage: expect $argv0 file host dir"
​
exit
​
}
​
set file [lindex $argv 0]
​
set host [lindex $argv 1]
​
set dir [lindex $argv 2]
​
set password "123456"
​
spawn scp -P22 -rp $file root@$host:$dir
​
expect {
​
"yes/no" {send "yes\r"; exp_continue}
​
"*password*" {send "$password\r"}
​
}
​
expect eof
​
[root@localhost ~]# chmod +x auto_upload_file.exp
​
[root@localhost ~]# ./auto_upload_file.exp
​
usage: expect ./auto_upload_file.exp file host dir
​
[root@localhost ~]# ./auto_upload_file.exp cpuinfo.sh
192.168.200.112 /opt
​
spawn scp -P22 -rp cpuinfo.sh root@192.168.200.112:/opt
​
root@192.168.200.112's password:
​
cpuinfo.sh 100% 1470 393.6KB/s 00:00

2)通过shell脚本中的循环语句,调取expect单机自动免交互上传文件脚本。从而实现将cpuinfo.sh脚本批量上传到客户机指定目录下。

[root@localhost ~]# vim auto_upload_files.sh
​
#!/bin/bash
​
# Filename : auto_upload_files.sh
​
if [ $# -ne 2 ]; then
​
echo "useage : sh $0 file dir"
​
exit 1
​
fi
​
file=$1
​
dir=$2
​
for IP in 192.168.200.{112..113} ; do
​
expect auto_upload_file.exp $file $IP $dir
​
done
​
[root@localhost ~]# chmod +x auto_upload_files.sh
​
[root@localhost ~]# ./auto_upload_files.sh
​
useage : sh ./auto_upload_files.sh file dir
​
[root@localhost ~]# ./auto_upload_files.sh cpuinfo.sh /opt/
​
spawn scp -P22 -rp cpuinfo.sh root@192.168.200.112:/opt/
​
root@192.168.200.112's password:
​
cpuinfo.sh 100% 1470 783.5KB/s 00:00
​
spawn scp -P22 -rp cpuinfo.sh root@192.168.200.113:/opt/
​
root@192.168.200.113's password:
​
cpuinfo.sh 100% 1470 662.7KB/s 00:00

3)通过expect实现自动免交互方式在指定单台客户机上执行指定命令或脚本程序。

[root@localhost ~]# vim auto_run_host.exp
​
#!/usr/bin/expect
​
# Filename: auto_run_1host.sh
​
if { $argc !=2 } {
​
puts "usage: expect $argv0 ip command"
​
exit
​
}
​
set ip [lindex $argv 0]
​
set cmd [lindex $argv 1]
​
set password "123456"
​
spawn ssh root@$ip $cmd
​
expect {
​
"yes/no" {send "yes\r"; exp_continue}
​
"*password*" {send "$password\r"}
​
}
​
expect eof
​
[root@localhost ~]# chmod +x auto_run_host.exp
​
[root@localhost ~]# ./auto_run_host.exp 192.168.200.112 "ifconfig
ens32"
​
spawn ssh root@192.168.200.112 ifconfig ens32
​
root@192.168.200.112's password:
​
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
​
inet 192.168.200.112 netmask 255.255.255.0 broadcast 192.168.200.255
​
inet6 fe80::20c:29ff:fe8c:f2d9 prefixlen 64 scopeid 0x20<link>
​
ether 00:0c:29:8c:f2:d9 txqueuelen 1000 (Ethernet)
​
RX packets 2650 bytes 1541675 (1.4 MiB)
​
RX errors 0 dropped 0 overruns 0 frame 0
​
TX packets 1874 bytes 236034 (230.5 KiB)
​
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
​
[root@localhost ~]# ./auto_run_host.exp 192.168.200.112 "source
/opt/cpuinfo.sh"
​
spawn ssh root@192.168.200.112 source /opt/cpuinfo.sh
​
root@192.168.200.112's password:
​
logical CPU number in total: 1
​
phycical CPU number in total: 1
​
core number in a physical CPU: 1
​
logical CPU number in a phycical CPU:1
​
Hyper threading is NOT enabled.

4)通过shell脚本中的循环语句,调取单机免交互自动执行脚本程序的expect脚本。从而实现在多台机器上免交互自动执行shell脚本。

[root@localhost ~]# vim auto_run_hosts.sh
​
#!/bin/bash
​
# Filename: auto_run_hosts.sh
​
if [ $# -ne 1 ]; then
​
echo "useage: $0 cmd"
​
exit 3
​
fi
​
cmd=$1
​
for IP in 192.168.200.{112..113}; do
​
expect auto_run_host.exp $IP "$cmd"
​
done
​
[root@localhost ~]# chmod +x auto_run_hosts.sh
​
[root@localhost ~]# ./auto_run_hosts.sh
​
useage: ./auto_run_hosts.sh cmd
​
[root@localhost ~]# ./auto_run_hosts.sh "source
/opt/cpuinfo.sh"
​
spawn ssh root@192.168.200.112 source /opt/cpuinfo.sh
​
root@192.168.200.112's password:
​
logical CPU number in total: 1
​
phycical CPU number in total: 1
​
core number in a physical CPU: 1
​
logical CPU number in a phycical CPU:1
​
Hyper threading is NOT enabled.
​
spawn ssh root@192.168.200.113 source /opt/cpuinfo.sh
​
root@192.168.200.113's password:
​
logical CPU number in total: 1
​
phycical CPU number in total: 1
​
core number in a physical CPU: 1
​
logical CPU number in a phycical CPU:1
​
Hyper threading is NOT enabled.


文章转载自:

http://Wx6yMHcM.qphdp.cn
http://igiP7mJy.qphdp.cn
http://LMvGsnkd.qphdp.cn
http://arajiNWu.qphdp.cn
http://fWO1Luz5.qphdp.cn
http://iqRSut88.qphdp.cn
http://Qrsd4Jyp.qphdp.cn
http://KtFtd4Sv.qphdp.cn
http://BOMLOeDY.qphdp.cn
http://JvaL1UKV.qphdp.cn
http://epcHqpcq.qphdp.cn
http://mEBgzyGq.qphdp.cn
http://OzvaCfQe.qphdp.cn
http://QOCEm1wp.qphdp.cn
http://blnoRPzG.qphdp.cn
http://8aBJVLmW.qphdp.cn
http://bLt2pNFA.qphdp.cn
http://jR1cJJ7Q.qphdp.cn
http://5GoIMTFu.qphdp.cn
http://uPrKiJ7R.qphdp.cn
http://S4KhCNaP.qphdp.cn
http://hPaI0cxv.qphdp.cn
http://Y3HAWLTh.qphdp.cn
http://Hc2XeeAz.qphdp.cn
http://8rufbWFV.qphdp.cn
http://eOl7xv63.qphdp.cn
http://mbdUDWNv.qphdp.cn
http://oDKEG1tN.qphdp.cn
http://oLvD2ZQH.qphdp.cn
http://6JTudJBu.qphdp.cn
http://www.dtcms.com/a/373411.html

相关文章:

  • 告别低效:构建健壮R爬虫的工程思维
  • Ubuntu中显示英伟达显卡的工具软件或者指令
  • 银行卡号识别案例
  • 【golang学习笔记 gin 】1.2 redis 的使用
  • AI提示词(Prompt)基础核心知识点
  • VTK开发笔记(五):示例Cone2,熟悉观察者模式,在Qt窗口中详解复现对应的Demo
  • Excel 表格 - Excel 减少干扰、专注于内容的查看方式
  • Vue3 + Ant Design Vue 全局配置中文指南
  • CSS in JS 的演进:Styled Components, Emotion 等的深度对比与技术选型指引
  • 哈士奇vs网易高级数仓:数据仓库的灵魂是模型、数据质量还是计算速度?| 易错题
  • Windows 命令行:cd 命令2,切换到多级子目录
  • C++ 8
  • GD32入门到实战45--LVGL开发(Code::Blocks)之创建控件
  • 算法题(202):乌龟棋
  • 国产化服务注册与发现工具nacos安装
  • WordPress 性能优化:从插件到 CDN 的全方位缓存设置指南
  • 所有微服务部署都使用一个git地址,并且通过docker部署各个服务的情况下,如何编写mvn指令来处理各个服务。
  • 【AI】乡村振兴计划书:AI智能农业与设备研发销售一体化项目
  • 408 Request Timeout:请求超时,服务器等待客户端发送请求的时间过长。
  • 从车辆中心到用户中心:E/E架构的变革与挑战
  • 基于Mysql+SpringBoot+vue框架-校园商铺管理系统源码
  • SQL MERGE语句实战:高效增量数据处理
  • AI 云再进化,百度智能云新技术与产品全景解读
  • react 面试题 react 有什么特点?
  • PyTorch 模型保存与加载 (速查版)
  • MCU-在SOTA过程中基于TC397的AB-SWAP切换底层原理
  • Python+DRVT 从外部调用 Revit:批量创建带孔洞楼板
  • 如何解决Ubuntu22.04安装Docker后使用Timeshift进行备份非常慢的问题
  • 自适应支撑衣专利拆解:IMU 传感器与线轴引擎的支撑力动态调节机制
  • Linux系统shell脚本(五)