Following on from my previous question, is it possible to make a Python script which persistently changes a Windows environment variable?
继我之前的问题之后,是否有可能制作一个持久更改Windows环境变量的Python脚本?
Changes to os.environ do not persist once the python interpreter terminates. If I were scripting this on UNIX, I might do something like:
一旦python解释器终止,对os.environ的更改不会保留。如果我在UNIX上编写脚本,我可能会这样做:
set foo=`myscript.py`
But alas, cmd.exe does not have anything that works like sh's back-tick behavior. I have seen a very long-winded solution... it 'aint pretty so surely we can improve on this:
但是,唉,cmd.exe没有像sh的后退行为一样的东西。我看到了一个非常冗长的解决方案......它确实非常可靠,我们可以改进这个:
for /f "tokens=1* delims=" %%a in ('python ..\myscript.py') do set path=%path%;%%a
Surely the minds at Microsoft have a better solution than this!
当然,微软的思想有一个比这更好的解决方案!
Note: exact duplicate of this question.
注意:这个问题的完全重复。
5 个解决方案
#1
Your long-winded solution is probably the best idea; I don't believe this is possible from Python directly. This article suggests another way, using a temporary batch file:
你啰嗦的解决方案可能是最好的主意;我不相信这可以直接来自Python。本文提出了另一种方法,使用临时批处理文件:
#2
You might want to try Python Win32 Extensions, developed by Mark Hammond, which is included in the ActivePython (or can be installed separately). You can learn how to perform many Windows related tasks in Hammond's and Robinson's book.
您可能想尝试由Mark Hammond开发的Python Win32 Extensions,它包含在ActivePython中(或者可以单独安装)。您可以在Hammond和Robinson的书中学习如何执行许多与Windows相关的任务。
Using PyWin32 to access windows COM objects, a Python program can use the Environment Property of the WScript.Shell
object - a collection of environment variables.
使用PyWin32访问Windows COM对象,Python程序可以使用WScript.Shell对象的Environment属性 - 环境变量的集合。
#3
Windows sets Environment variables from values stored in the Registry for each process independently.
Windows为每个进程独立地存储在注册表中的值设置环境变量。
However, there is a tool in the Windows XP Service Pack 2 Support Tools named setx.exe that allows you to change global Environment variables from the command line.
但是,Windows XP Service Pack 2支持工具中有一个名为setx.exe的工具,允许您从命令行更改全局环境变量。
#4
My solution using win32api:
我使用win32api的解决方案:
import os, sys, win32api, win32con
'''Usage: appendenv.py envvar data_to_append'''
def getenv_system(varname, default=None):
'''
Author: Denis Barmenkov <barmenkov at bpc.ru>
Copyright: this code is free, but if you want to use it,
please keep this multiline comment along with function source.
Thank you.
2006-01-28 15:30
'''
v = default
try:
rkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment')
try:
v = str(win32api.RegQueryValueEx(rkey, varname)[0])
v = win32api.ExpandEnvironmentStrings(v)
except:
pass
finally:
win32api.RegCloseKey(rkey)
return v
#My set function
def setenv_system(varname, value):
try:
rkey = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment',0 ,win32con.KEY_WRITE)
try:
win32api.RegSetValueEx(rkey, varname, 0, win32con.REG_SZ, value)
return True
except Exception, (error):
pass
finally:
win32api.RegCloseKey(rkey)
return False
if len(sys.argv) == 3:
value = getenv_system(sys.argv[1])
if value:
setenv_system(sys.argv[1],value + ";" + sys.argv[2])
print "OK! %s = %s" % (sys.argv[1], getenv_system(sys.argv[1]))
else:
print "ERROR: No such environment variable. (%s)" % sys.argv[1]
else:
print "Usage: appendenv.py envvar data_to_append"
#5
This link provides a solution that uses the built-in winreg
library.
此链接提供使用内置winreg库的解决方案。
(copypasta)
import sys
from subprocess import check_call
if sys.hexversion > 0x03000000:
import winreg
else:
import _winreg as winreg
class Win32Environment:
"""Utility class to get/set windows environment variable"""
def __init__(self, scope):
assert scope in ('user', 'system')
self.scope = scope
if scope == 'user':
self.root = winreg.HKEY_CURRENT_USER
self.subkey = 'Environment'
else:
self.root = winreg.HKEY_LOCAL_MACHINE
self.subkey = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
def getenv(self, name):
key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_READ)
try:
value, _ = winreg.QueryValueEx(key, name)
except WindowsError:
value = ''
return value
def setenv(self, name, value):
# Note: for 'system' scope, you must run this as Administrator
key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_ALL_ACCESS)
winreg.SetValueEx(key, name, 0, winreg.REG_EXPAND_SZ, value)
winreg.CloseKey(key)
# For some strange reason, calling SendMessage from the current process
# doesn't propagate environment changes at all.
# TODO: handle CalledProcessError (for assert)
check_call('''\
"%s" -c "import win32api, win32con; assert win32api.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')"''' % sys.executable)
#1
Your long-winded solution is probably the best idea; I don't believe this is possible from Python directly. This article suggests another way, using a temporary batch file:
你啰嗦的解决方案可能是最好的主意;我不相信这可以直接来自Python。本文提出了另一种方法,使用临时批处理文件:
#2
You might want to try Python Win32 Extensions, developed by Mark Hammond, which is included in the ActivePython (or can be installed separately). You can learn how to perform many Windows related tasks in Hammond's and Robinson's book.
您可能想尝试由Mark Hammond开发的Python Win32 Extensions,它包含在ActivePython中(或者可以单独安装)。您可以在Hammond和Robinson的书中学习如何执行许多与Windows相关的任务。
Using PyWin32 to access windows COM objects, a Python program can use the Environment Property of the WScript.Shell
object - a collection of environment variables.
使用PyWin32访问Windows COM对象,Python程序可以使用WScript.Shell对象的Environment属性 - 环境变量的集合。
#3
Windows sets Environment variables from values stored in the Registry for each process independently.
Windows为每个进程独立地存储在注册表中的值设置环境变量。
However, there is a tool in the Windows XP Service Pack 2 Support Tools named setx.exe that allows you to change global Environment variables from the command line.
但是,Windows XP Service Pack 2支持工具中有一个名为setx.exe的工具,允许您从命令行更改全局环境变量。
#4
My solution using win32api:
我使用win32api的解决方案:
import os, sys, win32api, win32con
'''Usage: appendenv.py envvar data_to_append'''
def getenv_system(varname, default=None):
'''
Author: Denis Barmenkov <barmenkov at bpc.ru>
Copyright: this code is free, but if you want to use it,
please keep this multiline comment along with function source.
Thank you.
2006-01-28 15:30
'''
v = default
try:
rkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment')
try:
v = str(win32api.RegQueryValueEx(rkey, varname)[0])
v = win32api.ExpandEnvironmentStrings(v)
except:
pass
finally:
win32api.RegCloseKey(rkey)
return v
#My set function
def setenv_system(varname, value):
try:
rkey = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment',0 ,win32con.KEY_WRITE)
try:
win32api.RegSetValueEx(rkey, varname, 0, win32con.REG_SZ, value)
return True
except Exception, (error):
pass
finally:
win32api.RegCloseKey(rkey)
return False
if len(sys.argv) == 3:
value = getenv_system(sys.argv[1])
if value:
setenv_system(sys.argv[1],value + ";" + sys.argv[2])
print "OK! %s = %s" % (sys.argv[1], getenv_system(sys.argv[1]))
else:
print "ERROR: No such environment variable. (%s)" % sys.argv[1]
else:
print "Usage: appendenv.py envvar data_to_append"
#5
This link provides a solution that uses the built-in winreg
library.
此链接提供使用内置winreg库的解决方案。
(copypasta)
import sys
from subprocess import check_call
if sys.hexversion > 0x03000000:
import winreg
else:
import _winreg as winreg
class Win32Environment:
"""Utility class to get/set windows environment variable"""
def __init__(self, scope):
assert scope in ('user', 'system')
self.scope = scope
if scope == 'user':
self.root = winreg.HKEY_CURRENT_USER
self.subkey = 'Environment'
else:
self.root = winreg.HKEY_LOCAL_MACHINE
self.subkey = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
def getenv(self, name):
key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_READ)
try:
value, _ = winreg.QueryValueEx(key, name)
except WindowsError:
value = ''
return value
def setenv(self, name, value):
# Note: for 'system' scope, you must run this as Administrator
key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_ALL_ACCESS)
winreg.SetValueEx(key, name, 0, winreg.REG_EXPAND_SZ, value)
winreg.CloseKey(key)
# For some strange reason, calling SendMessage from the current process
# doesn't propagate environment changes at all.
# TODO: handle CalledProcessError (for assert)
check_call('''\
"%s" -c "import win32api, win32con; assert win32api.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')"''' % sys.executable)