subprocess.call() - 无法解析JSON(词法错误:JSON文本中无效字符)

2 投票
1 回答
684 浏览
提问于 2025-04-29 15:42
import subprocess
subprocess.call("mpc toggle", shell=True)

我正在尝试修改一个Python脚本,以便运行一个shell程序。我是通过subprocess.call()来实现的,代码如下:

def on_leftclick(self):
    import subprocess
    subprocess.call("mpc toggle", shell=True)

当我左键点击时,我遇到了这个错误:

Could not parse JSON (lexical error: invalid char in json text.)

这个操作是在i3pystatus中进行的,i3pystatus是一个与i3bar(i3窗口管理器的一部分)连接的程序。我已经修改过另一个脚本,并且它运行得很好,示例如下:

def on_upscroll(self):
    import subprocess
    subprocess.call("pamixer --increase 1 --allow-boost", shell=True)

另外,我还尝试在Python命令行中这样做,结果是成功的,所以我不明白问题出在哪里。

任何帮助都将非常感谢。

暂无标签

1 个回答

0

这个问题是因为在i3pystatus模块中这样做造成的:

subprocess.call("mpc toggle") # parameter shell=True or False, doesn't matter

因为默认情况下,subprocess.call()函数会把父进程(也就是)的输出和错误信息的处理方式传给新的子进程(mpc)。这样一来,mpc的所有输出都会直接混进的输出里。这个输出本来应该是有效的JSON格式,但现在却夹杂了一大堆意外的控制台信息。这就导致的输出无法被正确解析为JSON了。

你有两个选择:

使用subprocess来捕获或处理子进程的输出

处理掉它:

def on_leftclick(self):
    subprocess.call("mpc toggle", shell=True, 
                    stdout=subprocess.DEVNULL)

或者,如果你想要输出,可以使用subprocess.Popen()

def on_leftclick(self):
    p = subprocess.Popen(['mpc', 'toggle'],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    out, err = p.communicate() # .decode() these to strings if appropriate
    retcode = p.returncode

使用i3pystatus中的run_through_shell助手

i3pystatus提供了一个助手来帮你封装subprocessi3pystatus.core.command.run_through_shell

from i3pystatus.core.command import run_through_shell

def on_leftclick(self):
    run_through_shell(["mpc", "toggle"])

或者,如果你想让你的shell来解析命令,可以给它传递这个字符串:

def on_leftclick(self):
    run_through_shell("mpc toggle", enable_shell=True)

你也可以轻松获取返回代码和标准输出/错误输出,方便你自己使用:

def on_leftclick(self):
    retcode, out, err = run_through_shell(["mpc", "toggle"])
    # out and err are already decoded to UTF-8 - you can't use this
    # method if that's not true, e.g. if it's binary data

公平地说,run_through_shell是在提问一年后才出现的(它是在2014年12月添加的)。i3pystatus的代码中同时使用了这两种方法。

总结:确保你的子进程不会把输出混入的输出中,因为那需要是有效的JSON。

* 可能在这个调用中导致json.loads()失败,但我还没有证明这一点。

撰写回答