python 脚本可以持续更改 Windows 环境变量吗?(优雅地)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/488449/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:54:01  来源:igfitidea点击:

Can a python script persistently change a Windows environment variable? (elegantly)

pythonwindowsscriptingbatch-file

提问by Salim Fadhley

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.

注意此问题的完全重复。

采纳答案by DNS

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 中实现。本文提出了另一种方法,使用临时批处理文件:

http://code.activestate.com/recipes/159462/

http://code.activestate.com/recipes/159462/

回答by gimel

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 PyWin32to access windows COM objects, a Python program can use the Environment Propertyof the WScript.Shellobject - a collection of environment variables.

使用PyWin32访问 windows COM 对象,Python 程序可以使用该对象的Environment 属性WScript.Shell- 环境变量的集合。

回答by Powerlord

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 Toolsnamed setx.exe that allows you to change global Environment variables from the command line.

但是,Windows XP Service Pack 2 支持工具中有一个名为 setx.exe 的工具,允许您从命令行更改全局环境变量。

回答by Maiku Mori

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"

回答by Jace Browning

This linkprovides a solution that uses the built-in winreglibrary.

链接提供了使用内置winreg库的解决方案。

(copypasta)

(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)