首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我有一个python脚本,它在Thonny IDE中工作得很好,但是在终端上失败了。

我有一个python脚本,它在Thonny IDE中工作得很好,但是在终端上失败了。
EN

Stack Overflow用户
提问于 2021-09-09 20:52:35
回答 1查看 311关注 0票数 1

首先,下面是代码:

代码语言:javascript
复制
#!/usr/bin/python3
import re, pexpect, os

file = '/home/homebridge/flags/Restart.flag'
f = open(file, 'w')
f.close()
os.system("sudo systemctl stop homebridge")
os.system("sudo chmod -R a+rwx /var/lib/homebridge")
child = pexpect.spawn('tuya-cli wizard')
child.expect('\r\n')
child.sendline('y')
child.expect('\r\n')
child.sendline('XXXXXXXXXXXXXXXX')
data = child.read()
data = data.decode("utf-8")
devices = data.split('},')
devicesO = []
class device:
    name = ""
    ID = ""
    key = ""
    
    def __init__(self, name, ID, key):
        self.name = name
        self.ID = ID
        self.key = key
        
    def __lt__(self, other):
        return self.name < other.name

for i in devices:


    n = re.search("name: \'(.*)\'", str(i)).group(1)
    I = re.search("id: \'(.*)\'", str(i)).group(1)
    k = re.search("key: \'(.*)\'", str(i)).group(1)
    if n != ("Clock"):
        devicesO.append(device(n, I, k))

entries = []
devicesO.sort()
for device in devicesO:
    if "phone charger" not in device.name:
        s1 = "{\n\"name\": \"" + device.name + "\",\n\"id\": \"" + device.ID + "\",\n\"key\": \"" + device.key + "\","
        s2 = """
"type": "RGBTWLight",
"manufacturer": "SmartLife",
"model": "Light",
"dpPower": "20",
"dpMode": "21",
"dpBrightness": "22",
"dpColorTemperature": "23",
"dpColor": "24",
"colorFunction": "HSB",
"scaleBrightness": 1000
}"""
    else:
        s1 = "{\n\"name\": \"" + device.name + "\",\n\"id\": \"" + device.ID + "\",\n\"key\": \"" + device.key + "\","
        s2 = """
"type": "Outlet",
"manufacturer": "SmartLife",
"model": "Outlet",
"dpPower": "1"
}"""
    entries.append(s1 + s2)
string = ",\n".join([str(entry) for entry in entries])
config = open('/var/lib/homebridge/config.json', 'r+')
x = config.read()
config.close()
#print(x)
x = re.sub("\"TuyaLan\",\n.*\"devices\": \[((.|\n)*?)\]", "\"TuyaLan\",\n\"devices\": [\n" + string + "\n]", x)
#print(x)
#x = re.sub("\"TuyaLan\",\n.*\"devices\": \[((.|\n)*?)\]", "\"TuyaLan\",\n.*\"devices\": [\nTEST\n]", x)
config = open('/var/lib/homebridge/config.json', 'w+')
config.write(x)
config.close()
config = open('/var/lib/homebridge/config.json', 'r+')
print (config.read())
config.close()
os.remove(file)
os.system("sudo systemctl restart homebridge")

这按照IDE中的预期执行,停止主桥服务,从tuya实用程序、regex和文本替换中提取相关数据,所有这些都是这样。但是,当我尝试在没有sudo的终端中运行它时,第一个regex搜索返回一个空对象,脚本就失败了。当我使用sudo运行它时,它会暂停一段时间,然后在pexpect步骤开始时超时。我在发帖之前已经做过调查,但我不知道如何解决这个问题。这似乎不是路径问题,我使用pip3同时安装re和pexpect,os显然是与raspbian安装一起打包的。任何线索都会很好。没有sudo的错误:

代码语言:javascript
复制
pi@raspberrypi:~ $ /home/homebridge/scripts/updateConfig.py
Traceback (most recent call last):
  File "/home/homebridge/scripts/updateConfig.py", line 34, in <module>
    n = re.search("name: \'(.*)\'", str(i)).group(1)
AttributeError: 'NoneType' object has no attribute 'group'

与sudo:

代码语言:javascript
复制
pi@raspberrypi:~ $ sudo /home/homebridge/scripts/updateConfig.py
Traceback (most recent call last):
  File "/home/homebridge/scripts/updateConfig.py", line 10, in <module>
    child.expect('\r\n')
  File "/usr/local/lib/python3.7/dist-packages/pexpect/spawnbase.py", line 344, in expect
    timeout, searchwindowsize, async_)
  File "/usr/local/lib/python3.7/dist-packages/pexpect/spawnbase.py", line 372, in expect_list
    return exp.expect_loop(timeout)
  File "/usr/local/lib/python3.7/dist-packages/pexpect/expect.py", line 181, in expect_loop
    return self.timeout(e)
  File "/usr/local/lib/python3.7/dist-packages/pexpect/expect.py", line 144, in timeout
    raise exc
pexpect.exceptions.TIMEOUT: Timeout exceeded.
<pexpect.pty_spawn.spawn object at 0x766c4510>
command: /usr/bin/tuya-cli
args: ['/usr/bin/tuya-cli', 'wizard']
buffer (last 100 chars): b'\x1b[32m?\x1b[39m \x1b[1mThe API key from tuya.com:\x1b[22m\x1b[0m \x1b[0m\x1b[29D\x1b[29C'
before (last 100 chars): b'\x1b[32m?\x1b[39m \x1b[1mThe API key from tuya.com:\x1b[22m\x1b[0m \x1b[0m\x1b[29D\x1b[29C'
after: <class 'pexpect.exceptions.TIMEOUT'>
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 1470
child_fd: 5
closed: False
timeout: 30
delimiter: <class 'pexpect.exceptions.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
searcher: searcher_re:
    0: re.compile(b'\r\n')
EN

回答 1

Stack Overflow用户

发布于 2021-11-22 17:16:21

可能的简短答案:您的IDE可能会自动添加带有sendline的回车,这就是为什么您的代码在IDE中运行,而不是在终端运行。Sendline添加行提要(\n),但不添加回车(\r)。您应该在每个sendline (例如,\r )之后添加一个child.sendline('XXXXXXXXXXXXXXXX\r')来完成CRLF (\r\n)。

长篇解释:

根据您的代码,当您生成子程序时,您希望得到一个CRLF。然而,pexpect搜索并不贪婪,他们将在第一次遇到CRLF时停止搜索。不幸的是,当我测试您的代码时,pexpect在您输入的命令之后停止在CRLF,而不是之后的提示符:

代码语言:javascript
复制
child = pexpect.spawn('tuya-cli wizard')
child.expect('\r\n')
print(child.before)

输出

b" tuya-cli wizard"

您应该寻找提示符或消息,例如The API key from tuya.com:Password:

代码语言:javascript
复制
# tuya-cli wizard
The API key from tuya.com:
The API secret from tuya.com:
Provide a 'virtual ID' of a device currently registered in the app:

代码语言:javascript
复制
# sudo tuya-cli wizard
Password: 

但是,我认为这两个错误的发生都是因为您没有在sendline中包含回车(\r)。第一个错误发生的原因是,在提示符The API key from tuya.com:处,您发送了'y',而不是'y\r',所以在提示符处没有输入任何内容。然后您搜索CRLF,但是由于您没有包含\r,所以pexpect在b" tuya-cli wizard"之后找到了原始的CRLF。

expect调用实际上导致回车,但不幸的是,您的代码现在落后了一步,并且正在与前一个提示符进行交互,而不是与当前提示符交互。这就是为什么data = child.read()最终读取了错误的输出,导致了一个NoneType对象。

第二个错误发生是因为pexpect光标移动到The API key from tuya.com:提示符,寻找一个CRLF。由于它是提示符,所以它不会以CRLF结尾,所以pexpect搜索超时(那些\x1b转义序列只是用于格式化和颜色):

代码语言:javascript
复制
pexpect.exceptions.TIMEOUT: Timeout exceeded.
args: ['/usr/bin/tuya-cli', 'wizard']
before (last 100 chars): b'\x1b[32m?\x1b[39m \x1b[1mThe API key from tuya.com:\x1b[22m\x1b[0m \x1b[0m\x1b[29D\x1b[29C'
searcher: searcher_re:
    0: re.compile(b'\r\n')

注意,在\r\n字节字符串中没有bufferbefore字节字符串。

我会做这样的事情:

代码语言:javascript
复制
...
while True:
    index = child.expect(
        ["Password:", "The API key from tuya.com:", pexpect.TIMEOUT, pexpect.EOF, ])
    if index == 0:
        password = getpass()  # You will need 'from getpass import getpass'
        child.sendline(password)  # CR's are usually not needed with variables
    elif index == 1:
        # This is what you want
        child.sendline("XXXXXXXXXXXXXXXX\r")
        break
    elif index == 2:
        raise RuntimeError("Search string not found.")
    elif index ==3:
        raise RuntimeError("Child closed.")

child.expect("The API secret from tuya.com:")
child.sendline("XXXXXXXXXXXXXXXX\r")
...

祝你的密码好运!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69124596

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档