expect 脚本,: no such file or directory

expect

假如有两台主机 A 和 B,希望从 A 主机 ssh 到 B 主机,然后在 B 主机执行一些命令,可行的命令是 ssh usrname@hostB "command",每次都要输入密码,同时并不能执行一些复杂的逻辑或命令,有没有办法能把复杂命令自动化呢?

expect 是用来进行自动化控制和测试的软件工具。我们运行命令、脚本或程序时,这些命令、脚本或程序都需要手工从终端输入运行的指令。利用expect,我们可以根据程序的输出提示,模拟标准输入,替代人工敲命令提供给程序,从而实现自动化交互执行。

# 例如一个远程登录到主机上执行相关命令的 expect 脚本可以这么写
#!/usr/bin/expect

set host "xx.xx.xx.xx"
set username "xxx"
set password "xxx"

spawn ssh -o "StrictHostKeyChecking no" $username@$host
expect "*assword*"
send "$password\r"
expect "*$*"
send "command\n"
expect "*$*"
send "exit\n"
expect eof

# 你也许感觉出来了整个执行流程的模式,expect 顾名思义,就是期待一个什么输出,然后执行一个动作。

通常场景的命令有:

命令作用
send接收一个字符串参数,并将该参数发送到进程
expect和 send 相反,通常用来等待一个进程的反馈,我们根据进程的反馈,再发送对应的交互命令
spawn启动一个进程,spawn 后的 send 和 expect 命令都是和使用 spawn 打开的进程进行交互
interact用于退出自动化,进入人工交互。比如我们使用spawn、send 和 expect 命令完成了 ftp 登陆主机,执行下载文件任务,在文件下载结束以后,希望仍然停留在 ftp 命令行状态,以便手动执行后续命令,使用 interact 命令就可以很好的完成这个任务
send_user接收一个字符串参数,向用户发送数据
set timeout xx设置超时时间,单位是 s,默认是 10
set send_slow {10 0.001}设置输入频率,每10个字符间隔1ms
sleep自动执行受限于系统响应等情况,有时会插入该语句等待执行完成,再执行下面的语句
exp_continue
expect {
    pattern {
        action
    } pattern {
        action
    } pattern {
        action
    }
}

最后一个 expect 语句后面的 send 语句都不执行,为了让所有 send 语句都执行,可以用一个不带 send 的 expect 语句结尾。
expect "*$*"
send "pwd\n"
send "ls -l\n"
send_user "suscess\n" # 执行
expect "*$*" # 可添加一个 expect

如果 spawn 了多个进程,怎么区分 send 命令发送给哪个进程呢?
send 命令可以带一些选项支持这些操作,如

spawn telnet ip port
set TELNETID $spawn_id
send -i $TELNETID 用来向不同进程发送命令,是进行多程序控制的关键参数
send -s "xxx"  s 代表 slowly,也就是控制发送的速度,这个参数使用的时候要与expect中的变量send_slow相关联

复杂的 shell 指令执行

需要注意的是 expect 无法识别 shell 的语法,所以如果用了复杂的 shell 命令,会报如下错误 xxx : no such file or directory。如果想要 expect 执行复杂的 shell 命令,可以这么做 spawn bash -c {your shell commands}

命令行参数获取

#!/usr/bin/expect 

 # 判断输入的参数是否为 3 个,如果不为 3 个,就打印错误信息,退出该程序。
 if { $argc != 3 } { 
 puts stderr "Usage: test1 host-address username host-password\n"
 exit 1 
 } 

 set timeout  60 
 set host [lindex $argv 0] # 命令行参数获取,从真实的参数开始计算,expect xx.exp ARG0 ARG1 ...
 set name [lindex $argv 1]
 set password [lindex $argv 2] 
 
 ##set host "192.168.0.4"
 ##set name “root”
 ##set password "cluster"
  
 # root 用户的 rsa key 放在 /root/.ssh 中,其他用户则放在 /home/$name/.ssh 
 if { $name == "root"} { 
    spawn scp /$name/.ssh/id_rsa.pub $name@$host:/tmp 
 } else { 
    spawn scp /home/$name/.ssh/id_rsa.pub $name@$host:/tmp 
 } 
 # 等待上个命令的响应
 expect { 
    "(yes/no)?" { 
        send "yes\n"
        expect "assword:"
        send "$pasword\n"
    }  "assword:" { 
        send "$password\n"
    } 
 } 
 
 # 输入密码后,拷贝成功,出现 100% 字符串,作为预期响应
 expect "100%"

 # 调用 ssh 以 $name 用户名登录到 $host 上
 spawn  ssh $name@$host 
 expect "assword:"
 send "$password\n"
 expect ":~#"
 
 # 将刚刚拷贝的 rsa key 添加到用户的 home 目录下的 ./ssh/authorized_keys 
 if { $name == "root"} { 
    send "cat /tmp/id_rsa.pub >> /root/.ssh/authorized_keys\n"
 } else { 
    send "cat /tmp/id_rsa.pub >> /home/$name/.ssh/authorized_keys\n"
 } 
 expect ":~#"
 
 # 操作成功后,退回 SSH 客户端机器
 send "exit\n"
 expect "#"

 # 下面将测试能否自动登录,不用输入密码
 spawn  ssh $name@$host 
 expect  { 
            "Welcome" { 
                send_user "Auto login the server successfully!"
            } "assword:" { 
                send_user "failed to login the server!"
            } 
 } 

 send "ls\n"
 expect ":~#"
 # 退出 $host 
 send "exit\n"
 # 程序结束
 expect eof

函数

# definition
proc funcname {para1 para2} {
    command
    command
}

funcname para1 para2

# if
if {xxx} {
    ...
} else {
    ...
}

# for
for {set i 0} {$i < xxx} {incr i} {
    ....
}

# foreach

# while
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值