在构建一个小的 Expect 脚本时,我注意到,执行脚本后,一些字符会自动出现在 bash 的输入中。我以前在其他程序上见过这种情况,但在这里我有一些可重现的东西。
我的期望脚本如下:
#!/usr/bin/expect
spawn ssh root@[lindex $argv 0]
expect "password:"
send "[lindex $argv 1]\r"
expect "~#"
这是结果:
user@PC:~$ expect test.exp 192.168.0.2 root
spawn ssh [email protected]
[email protected]'s password:
^[[51;117Rroot@device:~# user@PC:~$ ;117R
-bash: syntax error near unexpected token `;'
user@PC:~$
正如您在输出的第五行中看到的那样,stdout ( ^[[51;117R
) 上有一些随机字符,其中一些泄漏到 shell 输入行 ( ;117R
) 上。如果我在执行 Expect 脚本后按 Enter 键,bash 会尝试解释该 ( ;117R
),就像我已将其输入到 bash 中一样。
我的问题是,这里发生了什么以及如何阻止它?
答案1
这些都是不是“随机字符”。
% printf '\e[51;117R' |控制台解码 ECMA48 心肺复苏术 51;117 %
在远程系统的登录过程中运行的操作是,通过向其终端发送设备状态报告控制序列,从该终端请求光标位置报告。终端(您的终端,几跳之外,通过ssh
和传递了 DSR 输出expect
)正在按时生成并发送它。
% printf '\x1b[6n' ;控制台解码 ECMA48 ^[[30;1R 心肺复苏 30;1 如果 %
此类报告从终端到达主机(即直接连接到终端的机器),其方式与键入输入完全相同。在主机上运行的程序没有可靠的方法来知道您不是简单地键入了光标位置报告。当然,expect
此时并没有在终端输入上读取和发送,因此 CPR 已排队等待下一个从终端读取输入的程序读取,该程序是expect
完成后的 shell。您所看到的是 shell 如何对输入等控制序列做出反应。
这些是终端输入处理实际上应该始终是具有适当状态机的适当 ECMA-48 解码器的原因之一。你的 shell 的行编辑系统不是。 (ZLE、Readline 或 libedit 都没有真正正确处理终端输入控制序列。)它使用模式匹配来解码内容,这并不能做正确的事情。请注意它如何仅忽略控制序列的前四个字符。适当的 ECMA-48 输入解码器将解码所有的控制序列,包括所有参数字符直到最终字符,将其识别为 CPR,并(希望)将其作为无用的输入丢弃。
至于首先请求 CPR 的是什么:为此,您必须检查远程系统,以及它在终端登录时运行的程序。罪魁祸首可能是 Xtermresize
程序。 (请注意,当 Xterm 不是您的终端时,您不应该使用该程序,因为它会将TERM
环境变量错误地设置为某种xterm
类型。)但这resize
并不是唯一的可能性。
进一步阅读
- 乔纳森·德博因·波拉德 (2018)。 ”
console-decode-ecma48
”。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2019)。 ”
TERM
”。 小吃指南。软件。 - https://unix.stackexchange.com/a/444270/5132