使用Expect在远程计算机上运行脚本

时间:2018-08-23 16:06:22

标签: linux shell scripting expect eof

我正在一个需要一些帮助的项目上。

我已经完成了完成该项目所需的大多数信息,但是唯一的滞后就是在远程计算机上运行本地Shell脚本。 我们知道,使用“ expect”库的脚本无法识别Linux命令。 这里我们尝试了两个用例:

1)仅使用一个期望脚本在远程服务器上运行所需的命令列表,该脚本既具有脚本执行功能,又具有使用scp将输出推送到本地计算机的功能,这是此代码的片段:

`chmod 777 localscript.sh   
cat > script1.sh <<- "ALL"`  
`#!/usr/bin/expect
set password [lindex $argv 0];  
set ipaddress [lindex $argv 1];  
set timevalue [lindex $argv 2];  
set timeout $timevalue  
spawn /usr/bin/ssh username@$ipaddress /bin/bash < ./localscript.sh  
expect "assword:"  
send "$password\r"  
set timeout $timevalue  
spawn /usr/bin/scp username@$2:"/path/from/source/*" /path/to/destination/folder/  
expect "assword:"  
send "$password\r"  
interact  
ALL  
chmod 777 script1.sh  
./script1.sh $password $2 $timevalue`  

2)在单独的Expect脚本中在远程服务器上运行所需的命令列表,并使用scp获取其他脚本中的文件:

`cat > script1.sh <<- "ALL" ` 
`#!/usr/bin/expect
set password [lindex $argv 0];  
set ipaddress [lindex $argv 1];  
set timevalue [lindex $argv 2];  
set timeout $timevalue   
spawn /usr/bin/ssh username@$ipaddress /bin/bash < ./localscript.sh  
expect "assword:"  
send "$password\r"  
interact  
ALL  
cat > script2.sh <<- "ALL2"`  
`#!/usr/bin/expect
set password [lindex $argv 0];  
set ipaddress [lindex $argv 1];  
set timevalue [lindex $argv 2];  
set timeout $timevalue   
spawn /usr/bin/scp username@ipaddress:"/path/from/source/*" /path/to/destination/folder/  
expect "assword:"  
send "$password\r"  
interact  
ALL2  
chmod 777 localscript.sh script1.sh script2.sh   
./script1.sh  $password $2 $timevalue  
sleep 5  
./script2.sh  $password $2 $timevalue`

我认为以上代码在各自方面都应该有效,但是,相同的输出似乎是出乎意料的:

1)输入密码后,几乎同时执行ssh和scp命令,因此它没有给本地脚本足够的时间来完成其工作,这是我看到的输出:

    spawn /usr/bin/ssh username@1.2.3.4 /bin/bash < ./localscript.sh  
    Warning private system unauthorized users will be prosecuted.  
    username@1.2.3.4's password: spawn /usr/bin/scp 
    username@1.2.3.4:"/home/some/file/*" /another/file/  
    Warning private system unauthorized users will be prosecuted.  
    username@1.2.3.4's password:  
    scp: /home/some/file/*: No such file or directory  

请注意:在没有期望的情况下,此功能可以正常工作

2)在这里,我们分别执行ssh和scp,但是似乎无法识别文件localscript.sh存在:

    spawn /usr/bin/ssh username@1.2.3.4 /bin/bash < ./localscript.sh  
    Warning private system unauthorized users will be prosecuted.  
    username@1.2.3.4's password:  
    bash: localscript.sh: No such file or directory  
    Warning private system unauthorized users will be prosecuted.  
    username@1.2.3.4's password:  
    scp: /home/some/file/*: No such file or directory  

任何有关此问题的反馈将不胜感激,我认为第一种方法可能是一种可行的解决方案,除了以下事实:生成速度太快并且“ sleep”或“ after”命令均无用/起作用。我认为第二种方法也是有效的,但是在远程服务器上运行本地脚本的方式似乎与使用“期望”时在Linux上的常规方式不同。

很抱歉,我希望尽快摆脱苦难:)

1 个答案:

答案 0 :(得分:0)

确实是您设置的超时在期望时不起作用。生成两个脚本,每次生成后的expect "assword:"实际上是在捕获并响应相同的密码提示。

expect实际上比凭空浏览会使您相信的更为复杂。每个spawn应该返回一个PID,您可以将其与expect一起使用,以查找特定进程的输出。

expect也可以分为多个部分,并且可以定义子例程。这是一些更高级的使用示例https://wiki.tcl-lang.org/10045

在这种情况下,我建议等待scp完成之后再生成下一个进程。

expect {
    "assword:" {
        send "$password\r"
        exp_continue # Keep expecting
    }
    eof {
        puts -nonewline "$expect_out(buffer)"
        # eof so the process should be done
        # It is safe to execute the next spawn
        # without exp_continue this expect will
        # break and continue to the next line
    }
}