考虑这个交互式脚本:
#!/usr/bin/env bash
set -eu
while true; do
read -p '> '
if [ "$REPLY" == quit ]; then
break
fi
echo "'$REPLY'"
done
现在我想expect
与它交互:
#!/usr/bin/env bash
set -eu
echo '
spawn ./1.sh
expect >
send cmd1\n
expect {\n> }
send quit\n
' | expect -d
但当我运行它时,它说:
...
expect: does " cmd1\r\n'cmd1'\r\n> " (spawn_id exp6) match glob pattern "\n> "? no
expect: timed out
send: sending "quit\n" to { exp6 }
为什么不匹配?如何检测新提示的出现(完成命令)?
答案1
在语言中,用和expect
tcl
引用的字符串是有区别的。你可以在两个例子中看到这一点:""
{}
$ expect -c 'puts "a\nb"'
a
b
~ $ expect -c 'puts {a\nb}'
a\nb
您的 glob 模式{\n> }
由 4 个要匹配的字符组成,但\n
不会被特殊解释为转义。如果你使用模式,"\n> "
你的匹配应该有效。或者您可以使用 flag-re
而不是默认的 glob 模式,并且这两个字符将被正则表达式代码解释为转义符-re {\n> }
.
答案2
太长了;博士添加-ex
标志。
这里的事情是expect
让事情变得更容易将复杂参数传递给某些命令 ( expect
/ interact
):
接受包含在单个列表中的参数(期望变体和交互)的命令使用启发式来确定列表实际上是一个参数还是多个参数。仅当列表实际上代表单个参数且该参数具有多个嵌入的 \n 且它们之间有非空白字符时,启发式方法才会失败。这看起来不太可能,但是参数“-nobrace”可用于强制将单个参数作为单个参数处理。可以想象,这可以与机器生成的 Expect 代码一起使用。类似地,-brace 强制将单个参数作为多个模式/操作进行处理。
(来自expect命令的描述)如果整个expect语句的参数需要多于一行,则所有参数可以“支撑”成一行,以避免以反斜杠终止每一行。在这种情况下,尽管有大括号,通常的 Tcl 替换仍然会发生。
我在这里举个例子:
#!/usr/bin/env bash
set -eu
f() {
echo line 1
sleep 1
echo line 2
}
export -f f
echo '
spawn bash -c f
expect {
{line 1} {puts 1}
{line 2} {puts 2}
}
expect \
{line 1} {puts 1} \
{line 2} {puts 2}
' | expect
输出:
spawn bash -c f
line 1
1
line 2
2
在我发现的存储库中,启发式在最新的提交(2014 年 5 月)中是如下:如果传递一个参数并且在第一个非空格之前有一个换行符,则该参数被认为是多个参数括成一个。