减少 Tcl/Expect 个语句 "greedy"

Making Tcl/Expect statements less "greedy"

考虑下面的 Expect 脚本。它创建一个测试文件,每行都有一个字符 (a,b,c,a,b,c),并使用 spawn:

打开文件
#!/usr/bin/expect -f

proc create_test_file {fname} {
    set chan [open $fname w]
    puts $chan "a\nb\nc"
    puts $chan "a\nb\nc"
    catch {close $chan}
}

log_user 0
create_test_file "test_file.txt"

set f [open "test_file.txt" r]
spawn -open $f

while {1} {
    expect {
        "c" { send_user "C\n" }
        "b" { send_user "B\n" }
        "a" { send_user "A\n" }
        eof { break }
    }
}

输出为:

C
C

输出是预期的,因为 expect 不会逐行处理文件,而是 而不是一下子。 expect语句的第一行"c"会丢弃第一行有a和b的,然后匹配第三行有c的,以此类推下一个循环。

其他 expect 语句也会匹配这些行,但它们永远没有机会这样做,因为第一个语句首先匹配,即使第一个语句丢弃了更多的行。

我想我理解这种行为,但现在我的问题是:是否有任何方法可以调整 expect 的行为,以便匹配的 expect 语句是需要丢弃文件中最少行的语句?这样生成的输出将变为以下内容:

A
B
C
A
B
C

默认模式是未锚定的。您可以使用 ^ 将它们作为正则表达式锚定到缓冲区的开头。例如,要逐个字符匹配,使用正则表达式 .:

跳过不匹配的字符
while {1} {
    expect {
        -re "^c" { send_user "C\n" }
        -re "^b" { send_user "B\n" }
        -re "^a" { send_user "A\n" }
        -re "^." { exp_continue }
        eof { break }
    }
}

虽然我在上面使用了正则表达式,但在这种情况下没有必要,因为默认的 "glob" 模式也接受 ^ 表示缓冲区的开始,因此您也可以使用

        "^c" { send_user "C\n" }
        "^b" { send_user "B\n" }
        "^a" { send_user "A\n" }
        "^?" { exp_continue }

其中 ? 匹配 glob 模式中的单个字符,相当于正则表达式中的 .