expect 中文手册:http://xstarcd.github.io/wiki/shell/expect_handbook.html
TCL 手册:https://www.yiibai.com/tcl/tcl_environment.html

执行

命令行中执行expect 脚本

expect可以让你使用“-c”选项,直接在命令行中执行它,如下所示:

$ expect -c ‘expect “\n” {send “pressed enter\n”}

pressed enter
$
如果你执行了上面的脚本,它会等待输入换行符(\n)。按“enter”键以后,它会打印出“pressed enter”这个消息,然后退出。

交互式执行 expect 脚本

使用“-i”选项,可以通过来自于标准输入的读命令来交互地执行expect脚本。如下所示:

$ expect -i arg1 arg2 arg3
expect1.1>set argv
arg1 arg2 arg3
expect1.2>

逐行执行

通常,expect会在执行脚本之前,把整个脚本都读入到内存中。“-b”选项可以让expect一次只读取脚本中的一行。当你没有写完整个脚本的时候,这是十分有用的,expect可以开始执行这个不完整的脚本,并且,它可以避免把脚本写入到临时文件中。

$ expect -b

示例

ssh 登录输入密码

登录 ssh 并获取输入权

  1. #file: jump.sh
  2. #!/usr/bin/expect
  3. set timeout 30
  4. spawn ssh -p 2222 xxxx@xxx.xxx.xx.com
  5. expect "*password:"
  6. send "password\r"
  7. interact

interact 是将tty 控制权交给用户

bash 里包裹 expect 代码

  1. #!/bin/bash
  2. passwd='123456'
  3. /usr/bin/expect <<-EOF
  4. set time 30
  5. spawn ssh saneri@192.168.56.103 df -Th
  6. expect {
  7. "*yes/no" { send "yes\r"; exp_continue }
  8. "*password:" { send "$passwd\r" }
  9. }
  10. expect eof
  11. EOF

使用命令行中的参数

  1. #!/usr/bin/expect
  2. set dir [lindex $argv 0]
  3. set name lixiaoguang
  4. set pwd WKCYmB1PIVZaUis
  5. cd /home/bae/wwwroot/$dir
  6. spawn git pull --rebase
  7. expect "*Username*"
  8. send "$name\n"
  9. expect "*Password*"
  10. send "$pwd\n"
  11. interact

示例四

#!/usr/bin/expect
set user [lindex $argv 0]   //第一个参数
set host [lindex $argv 1]   //第二个参数
set passwd "123123a"
set cm [lindex $argv 2]   //第三参数
spawn ssh $user@$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"

更多示例
https://www.cnblogs.com/saneri/p/10819348.html

登录远程服务器后继续执行其他命令

方式1 后续执行的命令放入的 “” 中

  • 双引号中写你需要在目标服务器上执行的脚本,
  • 支持换行,不用加\
  • 两个命令之间需要使用分号‘;’隔开。

如果脚本内容过于复杂,你可以在目标服务器上写好一个可执行的脚本文件 example.sh ,然后讲双引号中的内容改成”./example.sh”来执行,有了这个功能基本就能实现所有的需求了。

spawn ssh admin@xxxxxx.com "
ls;
pwd;
tail -n sdfsdfsdf.log
"

expect "password"
send "xxxxx\r"
expect eof

方式2:bash expect 穿插执行

#!/bin/bash
read -s PWD
/usr/bin/expect <<EOD
spawn ssh admin@koubei.inc.alipay.net "
ls;
tail kb-webroot/server/Resources/Cookies/stable_Cookie.cookie"
expect "password"
send "$PWD\n" 
expect eof
EOD
ls
echo "call me crazy"

若果你需要先在本地环境执行脚本拿到一些参数,然后传递给目标服务器,最后在目标服务器获得结果之后回到本地shell,这时候就需要穿插使用。

关键字

spawn 交互程序开始后面跟命令或者指定程序
expect 获取匹配信息匹配成功则执行expect后面的程序动作
expect eof 这个一定要加,与spawn对应表示捕获终端输出信息终止,类似于if….endif
send exp_send 用于发送指定的字符串信息
exp_continue 在expect中多次匹配就需要用到
send_user 用来打印输出 相当于shell中的echo
exit 退出expect脚本
eof expect执行结束 退出
set 定义变量
puts 输出变量
set timeout 设置超时时间

变量

定义变量

#!/usr/bin/expect
#设置expect 命令等待的超时时间,单位秒
set timeout 30
set name ll

获取脚本变量

#!/usr/bin/expect
#设置expect 命令等待的超时时间,单位秒
set timeout [lindex $argv 0]    #第一个脚本参数
set name [lindex $argv 1]    #第二个脚本参数

处理变量

#!/usr/bin/expect
#设置expect 命令等待的超时时间,单位秒
set timeout [lindex $argv 0]
set timeout2 [exec dc -e $timeout]    #处理变量

输入变量

#!/usr/bin/expect
set timeout 30

puts "$timeout"

交互

执行命令,并进行匹配

#!/usr/bin/expect
...
spawn ssh -l username 192.168.1.1

匹配期待输出

#!/usr/bin/expect
...
expect "password:"
#这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是前面设置的30秒

输入内容

#!/usr/bin/expect
...
send "ispass\r"

复合写法

spawn ssh root@$ip       //发送ssh请滶  
 expect {                 //返回信息匹配  
 "*yes/no" { send "yes\r"; exp_continue}  //第一次ssh连接会提示yes/no,继续  
 "*password:" { send "$password\r" }      //出现密码提示,发送密码  
 }  

#继续执行其他命令
expect "#*"  
  send "pwd\r"  
  send  "exit\r"  
  expect eof

嵌套写法

#!/usr/bin/expect  
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\n"  
    expect "*assword:" { send "$password\n"}  
 }  
 "*assword:"  
{  
 send "$password\n"  
}  
}  
expect "100%"  
expect eof

结束方式

保持交互状态

#!/usr/bin/expect
...
interact

退出

#!/usr/bin/expect
...
expect eof

相互调用

bash 里调用 expect

vim send_key.sh

#!/bin/bash    
ssh-keygen -t dsa    
for (( i = 1; i <= 100 ; i ++ ))    
do    
  ./scp_key_to_node.exp $i    
done


vim scp_key_to_node.exp

#!/usr/bin/expect    
set timeout 5    
set hostno [lindex $argv 0]    
spawn scp ~/.ssh/id_dsa.pub impala$hostno:~/.ssh/pub_key    
expect "*password*"    
send "111111\r"    
spawn ssh impala$hostno "cat ~/.ssh/pub_key/ >> ~/.ssh/authorized_keys"    
expect "*password*"    
send "111111\r"    
spawn ssh impala$hostno "chmod 600 ~/.ssh/authorized_keys"    
expect "*password*"    
send "111111\r"    
expect eof
#!/bin/bash  
USER=mynameuser  
PASS=oldpassword  
NPASS=newpassword  
expect << EOF  
  spawn passwd  
  expect "Changing password for ${USER}."  
  send "${PASS}\r"  
  expect "Enter new UNIX password:"  
  send "${NPASS}\r"  
  expect "Retype new UNIX password:"  
  send "${NPASS}\r"  
  expect eof;  
EOF