Expect/Tcl: 'string map' 删除字符串中的内容?
Expect/Tcl: 'string map' removing content in string?
设置: Expect/Tcl Linux
中的脚本
用例:
使用expect
等待在$user_command
中使用的某些状态的报告。
expect -re "notify (.+)\n"
set status $expect_out(1,string)
send [string map [list SESSION "$status"] "$user_command"]
所以当应用程序发送“notify running
”时,那么status
就会被设置为running
。
为此,$user_command
中的关键字 STATUS
需要替换为 $status
,例如
"log STATUS to file"
变成
"log running to file"
为了看什么开心,我写了
expect_tty -re "(.+)\n"
set status $expect_out(1,string)
send_user [string map [list SESSION "$status"] "$user_command"]
当 运行 单独使用时效果很好。输出是
log someUserInput to file
当键入 someUserInput
以响应 expect_tty
时。但是,作为更大脚本的一部分,字符串映射命令会在字符串替换之前删除任何内容,因此输出变为
" to file"
(没有换行符)我检查了脚本中变量的唯一性,所以这不是问题。
问题:
这是怎么回事?我怎样才能使脚本健壮?
string map
命令完全 是确定性的。在其输入字符串的每个字符处,它按顺序考虑映射列表中的 from 字符串是否按顺序匹配,如果匹配,则执行替换(使用成对的 to string) 并继续考虑紧接在被替换子字符串之后的字符。 (空字符串是一种特殊情况:它 never 匹配。)实现它的代码确实很愚蠢,但碰巧在现代计算机上对缓存非常友好,所以它仍然非常快;已经尝试了更复杂和据说“更快”的实现,但发现在实践中对于通常在野外遇到的各种地图来说速度较慢。
如果替换应用失败,通常是因为输入的字符串与您期望的不完全相同。在大多数程序中,这很少见,但在 expect 程序中更常见,因为它们内部的终端仿真引擎的输出可以包含用于移动光标和更改颜色等操作的元字符。 (通常最简单的解决方法是告诉生成的程序它的终端类型不支持这种复杂的功能,也许通过将 TERM
环境变量设置为 dumb
。)
感谢@glennjackman:
问题是由于应用程序将换行符报告为 \r\n
,因此 (.*)\n
in
expect_tty -re "(.+)\n"
匹配表达式 1(括号内的内容)末尾包含 \r
的内容。 \r
删除了它之前的任何内容,string map
似乎删除了被替换字符串之前的任何内容。解决方案是期待排除 \r
的内容,即
expect -re ``(\[^\r\n\]+)``
它收集所有内容直到行尾,无论格式如何。
设置: Expect/Tcl Linux
中的脚本用例:
使用expect
等待在$user_command
中使用的某些状态的报告。
expect -re "notify (.+)\n"
set status $expect_out(1,string)
send [string map [list SESSION "$status"] "$user_command"]
所以当应用程序发送“notify running
”时,那么status
就会被设置为running
。
为此,$user_command
中的关键字 STATUS
需要替换为 $status
,例如
"log STATUS to file"
变成
"log running to file"
为了看什么开心,我写了
expect_tty -re "(.+)\n"
set status $expect_out(1,string)
send_user [string map [list SESSION "$status"] "$user_command"]
当 运行 单独使用时效果很好。输出是
log someUserInput to file
当键入 someUserInput
以响应 expect_tty
时。但是,作为更大脚本的一部分,字符串映射命令会在字符串替换之前删除任何内容,因此输出变为
" to file"
(没有换行符)我检查了脚本中变量的唯一性,所以这不是问题。
问题:
这是怎么回事?我怎样才能使脚本健壮?
string map
命令完全 是确定性的。在其输入字符串的每个字符处,它按顺序考虑映射列表中的 from 字符串是否按顺序匹配,如果匹配,则执行替换(使用成对的 to string) 并继续考虑紧接在被替换子字符串之后的字符。 (空字符串是一种特殊情况:它 never 匹配。)实现它的代码确实很愚蠢,但碰巧在现代计算机上对缓存非常友好,所以它仍然非常快;已经尝试了更复杂和据说“更快”的实现,但发现在实践中对于通常在野外遇到的各种地图来说速度较慢。
如果替换应用失败,通常是因为输入的字符串与您期望的不完全相同。在大多数程序中,这很少见,但在 expect 程序中更常见,因为它们内部的终端仿真引擎的输出可以包含用于移动光标和更改颜色等操作的元字符。 (通常最简单的解决方法是告诉生成的程序它的终端类型不支持这种复杂的功能,也许通过将 TERM
环境变量设置为 dumb
。)
感谢@glennjackman:
问题是由于应用程序将换行符报告为 \r\n
,因此 (.*)\n
in
expect_tty -re "(.+)\n"
匹配表达式 1(括号内的内容)末尾包含 \r
的内容。 \r
删除了它之前的任何内容,string map
似乎删除了被替换字符串之前的任何内容。解决方案是期待排除 \r
的内容,即
expect -re ``(\[^\r\n\]+)``
它收集所有内容直到行尾,无论格式如何。