1

我正在构建一个简单的 ssh 登录包装工具来帮助自动登录到众多服务器中的一个。
它首先从用户输入中获取描述,然后提取相应的(最相关的)服务器 IP 和安全存储在某处的密码,并使用它创建一段期望脚本。

期望脚本看起来像这样:

    spawn ssh2 -q -t Bob@172.23.24.35
    预计 {
        "assword:" {发送 "Bob123\r"}
    }
    相互影响

当我通过管道将其传递给期望(期望可以从标准输入读取脚本)时,一切都很顺利,直到它达到“交互”。期望声称它接收到 eof 并立即终止。然后我将它存储到一个文件中说 tmp.exp 时发生同样的问题我做“expect < tmp.exp”。但是当我执行“expect -f tmp.exp”时,一切正常。

我认为原因是“交互”从 fd0 获取输入,该输入被我的程序(或 shell)重定向到管道。这是否意味着当我执行“expect < xx.exp”之类的操作时不能使用交互?有没有办法在“交互”命令之前将 fd0 恢复到真实终端?我用谷歌搜索了很多,我得到的只是'close_on_eof 0'之类的东西。我找不到它的含义,也找不到它是如何工作的。提前致谢!

4

2 回答 2

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。

于 2013-03-13T08:45:27.630 回答
2

不确定是否TclExpect提供了一种内置方法来检查文件描述符是否为 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
$
于 2013-03-18T03:00:18.337 回答