减少 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 模式中的单个字符,相当于正则表达式中的 .
。
考虑下面的 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 模式中的单个字符,相当于正则表达式中的 .
。