考虑这个交互式脚本:
#!/usr/bin/env bash
set -eu
while true; do
read -p '> '
if [ "$REPLY" == quit ]; then
break
fi
echo "'$REPLY'"
done
Run Code Online (Sandbox Code Playgroud)
现在我想expect与它交互:
#!/usr/bin/env bash
set -eu
echo '
spawn ./1.sh
expect >
send cmd1\n
expect {\n> }
send quit\n
' | expect -d
Run Code Online (Sandbox Code Playgroud)
但当我运行它时,它说:
...
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 }
Run Code Online (Sandbox Code Playgroud)
为什么不匹配?如何检测新提示的出现(完成命令)?
tl;dr添加-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
Run Code Online (Sandbox Code Playgroud)
输出:
spawn bash -c f
line 1
1
line 2
2
Run Code Online (Sandbox Code Playgroud)
在我发现的存储库中,最新提交(2014 年 5 月)中的启发式如下:如果传递一个参数并且在第一个非空格之前有一个换行符,则该参数被认为是多个参数合并成一个。