我正在构建一个简单的ssh登录包装工具,以帮助自动登录到很多服务器中的一个。
它首先从用户输入中获取描述,然后提取在某处安全存储的相应(最相关)服务器IP和密码,使用它创建一个expect脚本。
expect脚本看起来像这样:
spawn ssh2 -q -t Bob@172.23.24.35 expect { "assword:" {send "Bob123\r"} } interact
当我管道这期望(期望可以从stdin读取脚本)的一切 顺利,直到达到“互动”。 期望声称它收到了eof和 立即终止。然后我把它存入一个文件说tmp.exp同样的问题 当我做“期望< tmp.exp”时会发生。但是当我执行“expect -f tmp.exp”时 一切都好。
我认为原因是“interaction”接受来自fd0的输入,fd0被我的程序(或shell)重定向到管道。 这是否意味着当我这样做时我无法使用互动 像“expect< xx.exp”这样的东西? 有没有办法在“交互”命令之前将fd0恢复到真正的终端? 我google了很多,我得到的就是'close_on_eof 0'。我找不到它的意义,也不知道它是如何运作的。提前谢谢!
答案 0 :(得分:3)
我想出办法来做到这一点。见这个例子:
$ cat foo.exp
if {[catch {
# Close stdin and reopen it as /dev/tty. Then we are
#+ connecting to a tty.
close stdin
open /dev/tty
} err]} {
puts stderr $err
exit 1
}
# Without this, inputed lines will be echo'ed twice.
set stty_init -echo
spawn bash --noprofile --norc
expect -re {bash-[.0-9]+(#|\$) }
interact
exit
$ expect < foo.exp
spawn bash --noprofile --norc
bash-4.2# ptree $$
705 screen -T dtterm -U
24164 bash
26826 expect
26827 bash --noprofile --norc
26830 ptree 26827
bash-4.2# exit
exit
$
为了使其更加智能,我们需要在开始时检查stdin
是否是tty。
答案 1 :(得分:1)
不确定Tcl
或Expect
是否提供内置方法来检查文件描述符是否为tty。我这样做了:
$ cat foo.exp
if { [catch { system {[[ -t 0 ]]} } error] } {
puts "stdin is not a tty"
} else {
puts "stdin is a tty"
}
$ expect foo.exp
stdin is a tty
$ expect < foo.exp
stdin is not a tty
$