使用Expect脚本通过cat命令远程复制文件失败求助
问题原因
你的Expect脚本失效的核心问题是:
- 重定向
> /tmp/localpassfile直接把ssh的标准输出(stdout)写入本地文件,但ssh的密码提示是输出到**标准错误流(stderr)**的 - Expect默认只监听spawn进程的stdout,因此无法捕获到密码提示,脚本会卡在
expect "assword"步骤 - 加上
-q参数会进一步抑制ssh的提示输出,加剧了这个问题
而直接在Shell执行命令时,终端会同时显示stdout和stderr内容,你能看到密码提示并输入,ssh的stdout也能正常写入文件,所以可以正常工作。
解决方法
方法一:用Shell包裹命令,合并stderr到stdout
通过sh -c包裹命令,把stderr合并到stdout,让Expect能捕获到密码提示,同时保证远程文件内容能写入本地:
#!/usr/bin/expect set timeout -1 spawn sh -c "/usr/bin/ssh root@testserver cat /tmp/passfile > /tmp/localpassfile 2>&1" expect "assword:" send "welcome1\r" expect eof
方法二:捕获输出后过滤写入文件
不提前做重定向,先让Expect捕获所有输出,过滤掉密码提示等无关内容后写入本地文件:
#!/usr/bin/expect set timeout -1 set local_file "/tmp/localpassfile" spawn /usr/bin/ssh root@testserver cat /tmp/passfile expect { "assword:" { send "welcome1\r" exp_continue } eof {} } # 过滤掉密码提示和输入的密码,只保留远程文件内容 set output [string map {"assword:" "" "welcome1" ""} $expect_out(buffer)] set output [string trim $output] # 写入本地文件 set fp [open $local_file w] puts $fp $output close $fp
方法三:强制分配伪终端
给ssh加上-tt参数强制分配伪终端,确保密码提示能被输出:
#!/usr/bin/expect set timeout -1 spawn /usr/bin/ssh -tt root@testserver cat /tmp/passfile > /tmp/localpassfile expect "assword:" send "welcome1\r" expect eof
内容的提问来源于stack exchange,提问作者mallikarjun mudumali
相关产品推荐
相关产品推荐

