为什么strip()能解决这个pexpect脚本问题?

0 投票
1 回答
814 浏览
提问于 2025-04-16 18:21

我有一个对象。

这个对象里面有一个叫做 connect() 的方法,它会启动一个 pexpect 进程。

这个启动的进程是一个自定义的串口接口。启动时,这个工具会打印出一个可以连接的串口设备菜单,像这样:

libftdi device (0): A6005jpt
libftdi device (1): acFX9DQf
Serial device (a) : /dev/cu.Bluetooth-PDA-Sync
Select a device by its letter (^D to abort): 

我的 connect() 方法会根据给定的设备名称(比如 'acFX9DQf')来决定传递哪个数字: (self.connection 是 pexpect 启动的进程)

USBSERIAL_DEVICE_NAME = "acFX9DQf"    

try:
    while self.connection.expect(['libftdi device \(([0-9])\): (.*)','Serial device']) == 0:
        if self.connection.match.group(2).strip() == USBSERIAL_DEVICE_NAME:
            # do stuff
except:
    # do stuff

现在,我的问题是我在主逻辑中多次调用 connect()kill() 这个进程,有时候在某次调用中,connect() 会意外地抛出一个 pexpect.TIMEOUT 异常。

例如,当我在逻辑中添加以下调试语句时,像这样:

USBSERIAL_DEVICE_NAME = "acFX9DQf"

try:
    while self.connection.expect(['libftdi device \(([0-9])\): (.*)','Serial device'], timeout=10) == 0:
        print "MATCHED A DEVICE LINE!"
        if self.connection.match.group(2).strip() == USBSERIAL_DEVICE_NAME:
            print "MATCHED THE DESIRED USBSERIAL..."

...我在多次调用 connect() 时得到这样的输出:

libftdi device (0): A6005jpt
MATCHED A DEVICE LINE!
libftdi device (1): acFX9DQf
MATCHED A DEVICE LINE!
MATCHED THE DESIRED USBSERIAL...
Serial device (a) : /dev/cu.Bluetooth-PDA-Sync
Select a device by its letter (^D to abort): 1

...然后,我的某次 connect() 调用会意外地出现....

libftdi device (0): A6005jpt
MATCHED A DEVICE LINE!
libftdi device (1): acFX9DQf
Serial device (a) : /dev/cu.Bluetooth-PDA-Sync
Select a device by its letter (^D to abort): MATCHED A DEVICE LINE!

<<EXCEPTION>>

但是,如果我把代码改成这样:

try:
    while self.connection.expect(['libftdi device \(([0-9])\): (.*)','Serial device'], timeout=10) == 0:
        devicename = self.connection.match.group(2).strip()
        if devicename == USBSERIAL_DEVICE_NAME:
            # do stuff

我的问题就解决了!我可以反复运行它,完全没有问题 - 没有异常,也没有任何其他问题。

那么,这到底是怎么回事呢?我甚至不知道从哪里开始解决这个问题。

1 个回答

1

我猜你遇到了一个 TIMEOUT 的错误。根据输出中“匹配到设备行!”这条消息的位置,我猜测 spawn 实例在测试匹配时有多行内容。当 pexpect 编译正则表达式时,它会设置 re.DOTALL,这样 .* 就会包括换行符和其他行。这导致对 USBSERIAL_DEVICE_NAME 的测试失败,循环继续进行下一次迭代。接下来的 expect 调用会被阻塞,因为没有额外的输入,这样你就会遇到超时。

要解决这个问题,你可以传入自己编译的正则表达式(不带 re.DOTALL 标志),或者修改 .*,让它明确不匹配换行符(例如 \S*)。

至于为什么把匹配的结果存储在一个变量中似乎能解决问题,我只能猜这引入了一个微妙的时间变化,防止 expect 同时接收到多行输入。

撰写回答