python - subprocess.Popen() 的每个实例都有自己的外壳吗?
问题描述
背景:我正在尝试制作一个通过 GUI (Tkinter)、Youtube_DL 和 FFmpeg 播放音乐的应用程序。实际应用程序完成后,它还需要 FFmpeg 作为环境变量才能工作。现在,我正在尝试确保创建“个人”FFmpeg 环境变量以使应用程序可移植(最后一步是使用 pyinstaller 制作 .exe 文件)。
问题:我正在尝试SET
通过以下方式为 FFmpeg 创建环境变量subprocess.Popen
:
add_ffmpeg = subprocess.Popen(f"IF EXIST {path2set} SET PATH=%PATH%;{path2set}", shell=True)
当我尝试echo %PATH%
(使用Popen
)应该存在的 FFmpeg 变量时,不是。我只需要知道我是否在浪费时间,SET
而是应该使用SETX
或者其他一些解决方案,我愿意被告知我做错了。
相关代码:
# get any sub-directory with ffmpeg in it's name
ffmpeg = glob(f"./*ffmpeg*/")
# proceed if there is a directory
if len(ffmpeg) > 0:
# double-check directory exists
ffmpeg_exist = path.isdir(ffmpeg[0])
if ffmpeg_exist:
print("FFmpeg: Found -> Setting Up")
# get the absolute path of the directories bin folder ".\ffmpeg-release-essentials.zip\bin"
path2set = f"{path.abspath(ffmpeg[0])}\\bin\\"
# add path of directory to environment variables
add_ffmpeg = subprocess.Popen(f"IF EXIST {path2set} SET PATH=%PATH%;{path2set}", shell=True)
add_ffmpeg.wait()
# print all of the current environment variables
list_vars = subprocess.Popen("echo %PATH%", shell=True)
list_vars.wait()
else:
print("FFmpeg: Missing -> Wait for Download...")
# download the ffmpeg file via direct link
wget.download("https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip")
# unzip the file
powershell = subprocess.Popen("powershell.exe Expand-Archive -Path './ffmpeg-release-essentials.zip' "
"-DestinationPath './'")
powershell.wait()
# remove the file
remove("./ffmpeg-release-essentials.zip")
# get any sub-directory with ffmpeg in it's name
ffmpeg = glob("./*ffmpeg*/")
# double-check directory exists
ffmpeg_exist = path.isdir(ffmpeg[0])
# proceed with if it exists
if ffmpeg_exist:
print("FFmpeg: Found -> Setting Up")
# get the absolute path of the directories bin folder ".\ffmpeg-release-essentials.zip\bin"
path2set = f"{path.abspath(ffmpeg[0])}\\bin\\"
# add path of directory to environment variables
add_ffmpeg = subprocess.Popen(f"IF EXIST {path2set} SET PATH=%PATH%;{path2set}", shell=True)
add_ffmpeg.wait()
# print all of the current environment variables
list_vars = subprocess.Popen("echo %PATH%", shell=True)
list_vars.wait()
else:
print("Something unexplained has gone wrong.")
exit(0)
解决方案
事实上,每个子进程都是一个单独的进程——这就是“子进程”的意思——这意味着如果你set
在一次subprocess
调用中进行了某些操作,它只会在该子进程中可见,而不是在它的父进程中,或者在你随后运行的其他子进程中。
一个常见的解决方案是将env
关键字参数subprocess
与您想要设置的任何变量一起传递给调用;
from pathlib import Path
from os import environ
env = environ.copy()
if Path(path2set).exists():
env['PATH'] = '%s;%s' % (path2set, env['PATH'])
subprocess.Popen([...], env=env)
当然,在很多情况下,在父进程中进行这种修改就足够了,并且让任何子进程都继承了新的值。(直接修改os.environment
,而不是复制,并env=env
从最后一行删除)。
子进程是否是外壳是一个单独的主题,与您的问题无关。微不足道,有了shell=True
它;但是就像在您的示例中一样,如果您的子进程是例如,powershell.exe
那么它就是一个外壳,因为它就是这样(shell=True
此外,它是相当多余的,并且可能是您希望尽可能避免的事情)。
推荐阅读
- node.js - 获取 Axios HTTP 获取请求的连接 ETIMEDOUT
- arrays - PSET4: Filter(less)
- c# - 触发器未检测到与其他对撞机的碰撞
- python - (内存) 访问 Dask 类型数组时的问题
- reactjs - React - 链接在 chrome 中生成 net::ERR_UNSAFE_REDIRECT
- github - 在不使用 HTML img 标签的情况下更改 github 风格的 markdown 中的图像大小?
- javascript - 为什么 JavaScript 中不存在 clientRight 或 clientBottom?
- inform7 - 在 Inform 7 中,进入容器的反义词是什么?
- mysql - MySQL问题找到当前薪酬最高的员工
- json - 如何加载json并提取到neo4j中的单独节点