为何subprocess.run()返回空值?如何获取指定虚拟环境的sys.path?
问题原因分析
这个问题我之前也碰到过,核心原因是subprocess传递参数的逻辑和shell解析命令的方式不一样:
当你在控制台直接执行命令时,shell会自动处理掉外层的单引号,把import sys; print(sys.path[-1])作为纯代码字符串传递给Python的-c参数。但用subprocess的列表参数模式时,每个元素都是直接传给目标程序的,不会经过shell的引号解析——你给-c传的是'import sys; print(sys.path[-1])'(带单引号的字符串),Python执行的其实是把这个带引号的字符串当成代码,而不是执行引号里面的内容。相当于你在Python里跑了:
exec("'import sys; print(sys.path[-1])'")
这当然不会有任何输出,因为只是定义了一个字符串,没有执行里面的代码逻辑。
解决方法
方法1:去掉多余的单引号
直接把-c对应的参数改成不带外层单引号的代码字符串即可:
import subprocess result = subprocess.run( ['/home/nicolas/.local/venvs/docker-compose/bin/python', '-c', 'import sys; print(sys.path[-1])'], stdout=subprocess.PIPE, text=True # 加上这个可以直接得到字符串,不用手动decode字节流 ) print(result.stdout.strip())
这样执行后就能得到和控制台完全一致的输出了。
方法2:更可靠地获取虚拟环境的site-packages路径
如果你只是想获取虚拟环境的核心依赖目录(site-packages),用Python的sysconfig模块会比读取sys.path最后一个元素更可靠——毕竟sys.path的顺序可能因环境配置变化而改变,但sysconfig返回的是标准的site-packages路径:
import subprocess result = subprocess.run( ['/home/nicolas/.local/venvs/docker-compose/bin/python', '-c', 'import sysconfig; print(sysconfig.get_path("site-packages"))'], stdout=subprocess.PIPE, text=True ) print(result.stdout.strip())
额外提示:不推荐的shell模式(谨慎使用)
如果你习惯了shell的写法,也可以把命令作为单个字符串传递,并设置shell=True,但这种方式存在安全风险(如果命令包含用户可控输入的话),非必要不推荐:
import subprocess result = subprocess.run( "/home/nicolas/.local/venvs/docker-compose/bin/python -c 'import sys; print(sys.path[-1])'", shell=True, stdout=subprocess.PIPE, text=True ) print(result.stdout.strip())
内容的提问来源于stack exchange,提问作者Nicolas K.
相关产品推荐
相关产品推荐

