使Tcl/Expect语句更少”;贪婪的;

使Tcl/Expect语句更少”;贪婪的;,tcl,expect,Tcl,Expect,考虑下面的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

考虑下面的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

默认情况下,模式是未编排的。您可以使用
^
将它们作为正则表达式锚定到缓冲区的开头。例如,要逐个字符进行匹配,请跳过带有regexp
的未匹配字符:

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模式中的单个字符,相当于regexp中的

默认情况下,模式是未编排的。您可以使用
^
将它们作为正则表达式锚定到缓冲区的开头。例如,要逐个字符进行匹配,请跳过带有regexp
的未匹配字符:

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 }

其中
匹配全局模式中的单个字符,相当于regexp中的

有不同的方法来执行您描述的操作,但您的实际用例是什么?注意,您的
put
应该是
put$chan
。是的,这是正确的。我在复制时出错。有不同的方法来执行您描述的操作,但您真正的用例是什么?请注意,您的
put
应该是
put$chan
。是的,这是正确的。我复制时出错了。太好了,可以了,谢谢!起初我不理解“^”的必要性,但后来我意识到它与新行匹配。此外,exp_continue在此处是可选的,因为存在外部循环。>^匹配expect已读取的缓冲区的开头,而不是任何特定字符。是的,我理解,但在您上面的回答中,如果省略了:-re“^.”{exp_continue}行,脚本将只打印一次,因为字符之间没有与换行符匹配的内容(A\nb\nc\na\nb\nc\n)。这就是我说它符合新行的意思。你是对的,我把
“^.”
误读为
“^”
!很抱歉,我会删除那条评论,稍后再删除这条。太好了,很有效,谢谢!起初我不理解“^”的必要性,但后来我意识到它与新行匹配。此外,exp_continue在此处是可选的,因为存在外部循环。>^匹配expect已读取的缓冲区的开头,而不是任何特定字符。是的,我理解,但在您上面的回答中,如果省略了:-re“^.”{exp_continue}行,脚本将只打印一次,因为字符之间没有与换行符匹配的内容(A\nb\nc\na\nb\nc\n)。这就是我说它符合新行的意思。你是对的,我把
“^.”
误读为
“^”
!很抱歉,我将删除该评论,稍后再删除此评论。