Python ptyprocess读取缺失末尾两行数据问题求助
ptyprocess读取bluetoothctl响应丢失内容及异常字符问题
问题现象
真实终端中执行bluetoothctl操作能得到包含18个值和末尾“OK”的完整响应,但通过ptyprocess的read方法只能获取13个值,丢失末尾的“OK”行,同时还会返回一个ESC字符。
相关代码
@staticmethod def communicate(write_uuid, read_uuid, data): # Requires a writable and a readable GATT uuid and data to be written # The method returns the data retrieved from the readable GATT uuid hex_string = '' for char in data: hex_string += hex(ord(char)) + ' ' timeout = .1 read_process = ptyprocess.PtyProcessUnicode.spawn(['/bin/bash']) commands = ['bluetoothctl', 'menu gatt', f'select-attribute {read_uuid}', 'notify on'] for command in commands: read_process.write(command + '\n') time.sleep(timeout) read_process.read(1) write_process = ptyprocess.PtyProcessUnicode.spawn(['/bin/bash']) commands = f'bluetoothctl <<EOF\nmenu gatt\nselect-attribute {write_uuid}\nwrite "{hex_string}"\nEOF\n' write_process.write(commands) time.sleep(timeout) write_process.read(1) time.sleep(timeout) hex_values = [] pattern = re.compile(r'\b[0-9a-fA-F]{2}\b') lines = read_process.read(size=10000).splitlines() for line in lines: print(line)
实际读取到的响应
[CHG] Attribute /org/bluez/hci0/dev_CE_EE_A8_9B_17_AC/service000b/char000e Value: [Device:/service000b/char000e]# 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 0.0, 0.0, 0.0, 0 [Device:/service000b/char000e]# 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e .0, 0.0, 0.0, 0. [Device:/service000b/char000e]# 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 0, 0.0, 0.0, 0.0 [Device:/service000b/char000e]# 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c , 0.0, 0.0, 0.0, [Device:/service000b/char000e][
预期完整响应
[Device:/service000b/char000e]# [CHG] Attribute /org/bluez/hci0/dev_CE_EE_A8_9B_17_AC/service000b/char000e Value: [Device:/service000b/char000e]# 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 0.0, 0.0, 0.0, 0 [Device:/service000b/char000e]# 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e .0, 0.0, 0.0, 0. [Device:/service000b/char000e]# 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 0, 0.0, 0.0, 0.0 [Device:/service000b/char000e]# 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c , 0.0, 0.0, 0.0, [Device:/service000b/char000e]# 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 0.0, 0.0, 0.0, [Device:/service000b/char000e]# 30 2e 30 2c 20 30 2e 30 20 4f 4b 0a 0.0, 0.0 OK.
解决方案
1. 调整等待逻辑与读取方式
问题核心是等待时间不足,导致bluetoothctl未输出完所有内容就开始读取;同时单次固定大小的read可能提前终止。修改方案如下:
@staticmethod def communicate(write_uuid, read_uuid, data): hex_string = ' '.join(hex(ord(char)) for char in data) # 合并为单个进程处理,减少时序干扰 process = ptyprocess.PtyProcessUnicode.spawn(['bluetoothctl']) time.sleep(0.2) # 执行GATT相关命令 commands = [ 'menu gatt', f'select-attribute {read_uuid}', 'notify on', f'select-attribute {write_uuid}', f'write "{hex_string}"' ] for cmd in commands: process.write(cmd + '\n') time.sleep(0.2) # 清空当前命令的输出缓冲区,避免残留数据干扰后续读取 while process.readable(): try: process.read_nonblocking(size=1024, timeout=0.1) except ptyprocess.PtyProcessTimeout: break # 循环读取直到捕获到"OK"标记,确保获取完整响应 full_output = "" while True: try: chunk = process.read_nonblocking(size=1024, timeout=0.5) full_output += chunk if "OK" in full_output: break except ptyprocess.PtyProcessTimeout: break # 过滤ESC字符(ASCII码27)并输出 cleaned_output = full_output.replace('\x1b', '') lines = cleaned_output.splitlines() for line in lines: print(line) process.close()
2. 关键优化点
- 合并进程:避免多进程同步问题,用单个进程处理所有bluetoothctl操作
- 延长等待时间:根据蓝牙设备响应速度调整sleep时长,确保命令执行完成
- 非阻塞读取:配合超时机制循环读取,确保捕获所有输出直到目标标记出现
- 清理异常字符:直接替换ESC字符(
\x1b),净化输出内容
内容的提问来源于stack exchange,提问作者sonus89
相关产品推荐
相关产品推荐

