从 Python 修改 Windows 环境变量的接口
问题描述
如何通过 Python 脚本持续修改 Windows 环境变量?(这是 setup.py 脚本)
How can I persistently modify the Windows environment variables from a Python script? (it's the setup.py script)
我正在寻找用于此的标准功能或模块.我已经熟悉 注册方式,但任何关于此的评论也是欢迎.
I'm looking for a standard function or module to use for this. I'm already familiar with the registry way of doing it, but any comments regarding that are also welcome.
解决方案
使用 setx 有一些缺点,特别是如果您尝试附加到环境变量(例如 setx PATH %Path%;C:mypath)这将每次运行时重复附加到路径,这可能是一个问题.更糟糕的是,它不区分机器路径(存储在 HKEY_LOCAL_MACHINE)和用户路径(存储在 HKEY_CURRENT_USER).您在命令提示符处看到的环境变量由这两个值的串联组成.因此,在调用 setx 之前:
Using setx has few drawbacks, especially if you're trying to append to environment variables (eg. setx PATH %Path%;C:mypath) This will repeatedly append to the path every time you run it, which can be a problem. Worse, it doesn't distinguish between the machine path (stored in HKEY_LOCAL_MACHINE), and the user path, (stored in HKEY_CURRENT_USER). The environment variable you see at a command prompt is made up of a concatenation of these two values. Hence, before calling setx:
user PATH == u
machine PATH == m
%PATH% == m;u
> setx PATH %PATH%;new
Calling setx sets the USER path by default, hence now:
user PATH == m;u;new
machine PATH == m
%PATH% == m;m;u;new
每次调用 setx 附加到 PATH 时,系统路径不可避免地会在 %PATH% 环境变量中重复.这些更改是永久性的,不会因重新启动而重置,因此会在机器的整个生命周期内累积.
The system path is unavoidably duplicated in the %PATH% environment variable every time you call setx to append to PATH. These changes are permanent, never reset by reboots, and so accumulate through the life of the machine.
试图在 DOS 中弥补这一点超出了我的能力范围.所以我转向了 Python.我今天想出的解决方案,通过调整注册表来设置环境变量,包括附加到PATH而不引入重复,如下:
Trying to compensate for this in DOS is beyond my ability. So I turned to Python. The solution I have come up with today, to set environment variables by tweaking the registry, including appending to PATH without introducing duplicates, is as follows:
from os import system, environ
import win32con
from win32gui import SendMessage
from _winreg import (
CloseKey, OpenKey, QueryValueEx, SetValueEx,
HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE,
KEY_ALL_ACCESS, KEY_READ, REG_EXPAND_SZ, REG_SZ
)
def env_keys(user=True):
if user:
root = HKEY_CURRENT_USER
subkey = 'Environment'
else:
root = HKEY_LOCAL_MACHINE
subkey = r'SYSTEMCurrentControlSetControlSession ManagerEnvironment'
return root, subkey
def get_env(name, user=True):
root, subkey = env_keys(user)
key = OpenKey(root, subkey, 0, KEY_READ)
try:
value, _ = QueryValueEx(key, name)
except WindowsError:
return ''
return value
def set_env(name, value):
key = OpenKey(HKEY_CURRENT_USER, 'Environment', 0, KEY_ALL_ACCESS)
SetValueEx(key, name, 0, REG_EXPAND_SZ, value)
CloseKey(key)
SendMessage(
win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')
def remove(paths, value):
while value in paths:
paths.remove(value)
def unique(paths):
unique = []
for value in paths:
if value not in unique:
unique.append(value)
return unique
def prepend_env(name, values):
for value in values:
paths = get_env(name).split(';')
remove(paths, '')
paths = unique(paths)
remove(paths, value)
paths.insert(0, value)
set_env(name, ';'.join(paths))
def prepend_env_pathext(values):
prepend_env('PathExt_User', values)
pathext = ';'.join([
get_env('PathExt_User'),
get_env('PathExt', user=False)
])
set_env('PathExt', pathext)
set_env('Home', '%HomeDrive%%HomePath%')
set_env('Docs', '%HomeDrive%%HomePath%docs')
set_env('Prompt', '$P$_$G$S')
prepend_env('Path', [
r'%SystemDrive%cygwinin', # Add cygwin binaries to path
r'%HomeDrive%%HomePath%in', # shortcuts and 'pass-through' bat files
r'%HomeDrive%%HomePath%docsinmswin', # copies of standalone executables
])
# allow running of these filetypes without having to type the extension
prepend_env_pathext(['.lnk', '.exe.lnk', '.py'])
不影响当前进程或父shell,但会影响运行后打开的所有cmd窗口,无需重启,可以安全地多次编辑重新运行,不会引入任何重复.
It does not affect the current process or the parent shell, but it will affect all cmd windows opened after it is run, without needing a reboot, and can safely be edited and re-run many times without introducing any duplicates.
相关文章