Командная строка для удаления переменной среды из конфигурации уровня ОС

182

Windows имеет setxкоманду:

Description:
    Creates or modifies environment variables in the user or system
    environment.

Таким образом, вы можете установить переменную следующим образом:

setx FOOBAR 1

И вы можете очистить значение следующим образом:

setx FOOBAR ""

Однако переменная не удаляется. Это остается в реестре:

Foobar

Так как бы вы на самом деле удалили переменную?

Питер Мортенсен
источник
3
setx просто устанавливает переменную. Вы просто закрываете эту линию.
Фокс Уилсон
1
см. также stackoverflow.com/questions/1472722/…
Брайан Бернс
Так как это заняло у меня много времени, также посмотрите superuser.com/q/297947/46834 для опций не командной строки.
Гари

Ответы:

217

Чтобы удалить переменную из текущей среды ( не навсегда):

set FOOBAR=

Чтобы окончательно удалить переменную из пользовательской среды (которая по умолчанию используется для setxэтого):

REG delete HKCU\Environment /F /V FOOBAR

Если переменная установлена ​​в системной среде (например, если вы изначально установили ее с помощью setx /M), запустите администратор:

REG delete "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /F /V FOOBAR

Примечание. Приведенные REGвыше команды не влияют ни на какие существующие процессы (и некоторые новые процессы, которые разветвляются из существующих процессов), поэтому, если важно, чтобы изменения вступили в силу немедленно, самый простой и надежный способ - выйти из системы и вернуться обратно. или перезагрузка. Если это не вариант или вы хотите копнуть глубже, у некоторых из других ответов здесь есть несколько полезных советов, которые могут подойти для вашего случая использования.

CupawnTae
источник
1
Это решение, похоже, не работает - или я неправильно понимаю что-то базовое. Я делаю setx JUNK Hello. Откройте новый cmd. Введите echo %JUNK%и получите Hello. Затем я делаю REG delete "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /F /V JUNKи подтверждаю, что значение пропало из реестра. Я открываю новый cmd и печатаю echo %JUNK%и все равно получаю Hello. Поиск в реестре показывает отсутствие JUNK. Пожалуйста, не говорите мне, что вам нужна перезагрузка!
caasjj
Спасибо за ответ. Я открываю новое командное окно из меню «Пуск». Я пробовал обе версии команды. На самом деле, первый раз, когда я набираю команду userсреды, это удается. Затем, когда я набираю команду, я получаю The system was unable to find the specified registry or key value. Кроме того, глобальный поиск JUNKв реестре regeditничего не дает. Тем не менее, когда я открываю новое командное окно (через Пуск / Аксессуары или cmd.exe в Run) и набираю echo %JUNK%, значение все еще там!
caasjj
1
Ах! Как вы думаете, что рационально для этого? Я всегда избегаю админ как можно больше - воспитание в UNIX / BSD / Linux. Спасибо большое за потрясающее усердие. +1
caasjj
4
возможно это просто семантика, но удаление (из реестра) вступает в силу немедленно. Среда не будет повторно инициализирована из реестра, пока вы снова не войдете в систему. Вы можете объединить 2 команды, чтобы удалить его из текущей среды (который удалит его из SETсписка для следующей оболочки cmd), а затем удалить его из реестра, например:SETX FOOBAR "" & REG delete HKCU\Environment /F /V FOOBAR
Лука
1
Причина, по которой среда не обновляется без перезагрузки, заключается в том, что explorer.exe не знает, что она обновлена. Смотрите мой ответ для полного объяснения и решения.
Джейми
72

Чтобы удалить переменную из текущего сеанса команды, не удаляя ее навсегда, используйте обычную встроенную setкоманду - просто не ставьте ничего после знака равенства:

set FOOBAR=

Для подтверждения запустите setбез аргументов и проверьте текущую среду. Переменная должна отсутствовать в списке полностью.

Примечание : это только удалит переменную из текущей среды - оно не сохранит изменения в реестре. Когда новый командный процесс запущен, переменная вернется.

Брайан Келли
источник
77
Это определенно НЕ ответ, и меня беспокоит то, что так много голосов. Это эффективно только для текущего сеанса команды. Запустите новое командное окно, и VAR вернулся.
Joescii
6
@joescii Ты находишь это удивительным? Это ответило на вопрос в названии вопроса. Очевидно, что название вопроса должно быть более конкретным.
oberlies
10
@oberlies Я не согласен с тем, что он отвечает на вопрос в заголовке, потому что это НЕ работает на уровне ОС, а только в текущем командном окне. Во-вторых, ваша точка зрения предполагает, что детали вопроса не имеют значения.
Joescii
3
@oberlies, к сожалению, редактирование, кажется, не добилось цели - оно все еще получает отклик. Я предполагаю, что люди находят это полезным, даже если это не отвечает на фактический вопрос, в этом случае возможно это заслуживает голосов (не так ли?). По крайней мере, он не помечен как принятый, что может ввести в заблуждение.
CupawnTae
3
Я должен прокомментировать, почему я проголосовал. Очевидно, потому что это работает только в текущем сеансе.
Ян Грейнджер
22

Это было рассмотрено довольно много, но есть важная часть информации, которая отсутствует. Надеюсь, я смогу помочь разобраться, как это работает, и немного облегчить усталых путешественников. :-)

Удалить из текущего процесса

Очевидно, что все знают, что вы просто делаете это, чтобы удалить переменную окружения из вашего текущего процесса:

set FOO=

Постоянное удаление

Существует два набора переменных среды: общесистемные и пользовательские.

Удалить переменную среды пользователя:

reg delete "HKCU\Environment" /v FOO /f

Удалить общесистемную переменную среды:

REG delete "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /F /V FOO

Применить значение без перезагрузки

Вот волшебная информация, которой не хватает! Вы задаетесь вопросом, почему после того, как вы это сделаете, когда вы запускаете новое командное окно, переменная окружения все еще там. Причина в том, что explorer.exe не обновил свою среду. Когда один процесс запускает другой, новый процесс наследует среду от процесса, который его запустил.

Есть два способа исправить это без перезагрузки. Самый грубый способ - убить процесс explorer.exe и запустить его снова. Вы можете сделать это из диспетчера задач . Однако я не рекомендую этот метод.

Другой способ - сообщить explorer.exe, что среда изменилась и что она должна перечитать ее. Это делается путем трансляции сообщения Windows (WM_SETTINGCHANGE). Это можно сделать с помощью простого скрипта PowerShell. Вы можете легко написать один, чтобы сделать это, но я нашел его в окне «Настройки окна обновления после сценариев изменений» :

if (-not ("win32.nativemethods" -as [type])) {
    add-type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessageTimeout(
            IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
            uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
        "@
}

$HWND_BROADCAST = [intptr]0xffff;
$WM_SETTINGCHANGE = 0x1a;
$result = [uintptr]::zero

[win32.nativemethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE,[uintptr]::Zero, "Environment", 2, 5000, [ref]$result);

Резюме

Поэтому, чтобы удалить переменную среды пользователя с именем «FOO» и отразить это изменение в процессах, которые вы запускаете впоследствии, выполните следующие действия.

  1. Сохраните сценарий PowerShell в файл (назовем его updateenv.ps1).
  2. Сделайте это из командной строки: reg delete "HKCU \ Environment" / v FOO / f
  3. Запустите updateenv.ps1.
  4. Закройте и снова откройте командную строку, и вы увидите, что переменная среды больше не определяется.

Обратите внимание, что вам, вероятно, придется обновить настройки PowerShell, чтобы разрешить запуск этого сценария, но я оставлю это как упражнение Google-fu для вас.

Джейми
источник
Есть ли какая-то особая причина, по которой вы не рекомендуете убивать и перезапускать проводник? Я делаю это все время.
Прометей
Ну, есть два, которые сначала приходят на ум. Во-первых, процессы принудительного уничтожения могут вызвать утечку памяти. Да, процессы должны быть «песочницами», но даже диспетчер задач Windows предупреждает вас не делать это слегка. Другая более личная причина - мое ОКР. Когда вы убиваете и перезапускаете Проводник, все ваши значки на панели задач, включая дубликаты, когда вы нажимаете на них, переставляются. Мне нравится, чтобы мои иконки оставались в том порядке, в котором я их открывал.
Джейми
1
Вот это да. Волшебная команда, которую я искал, действует как source .bashrc(или ее двоюродные братья) в Windows. Это относится к началу строки "отсылка к этому" для меня.
bballdave025
19

Из PowerShell вы можете использовать [System.Environment]::SetEnvironmentVariable()метод .NET :

  • Чтобы удалить переменную среды пользователя с именем FOO:

    [Environment]::SetEnvironmentVariable('FOO', $null, 'User')
    

Обратите внимание, что $nullэто используется, чтобы лучше сигнализировать о намерении удалить переменную, хотя технически это фактически то же самое, что и передача ''в этом случае.

  • Для удаления системной (на уровне компьютера) переменной среды с именем FOO- требуется повышение прав (необходимо запускать с правами администратора):

    [Environment]::SetEnvironmentVariable('FOO', $null, 'Machine')
    

Помимо более быстрого выполнения, преимущество по сравнению с reg.exeметодом на основе заключается в том, что другие приложения уведомляются об изменении посредством WM_SETTINGCHANGEсообщения (хотя не все приложения прослушивают это сообщение).

mklement0
источник
2
Это лучший ответ здесь.
Джеймс
1
Этот метод избавляет от необходимости перезагрузки. Какое элегантное решение!
Цзяо
13

Я согласен с CupawnTae .

SET бесполезен для изменений в основной среде.

К сведению: системные переменные находятся в HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment(гораздо дольше, чем пользовательские переменные).

Поэтому полная команда для системной переменной с именем FOOBAR:

REG delete "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /F /V FOOBAR

(Обратите внимание на кавычки, необходимые для обработки пробела.)

Жаль, что setxкоманда не поддерживает синтаксис удаления. :(

PS: Используйте ответственно - если вы убьете свою переменную пути, не вините меня!

DougWare
источник
@CMCDragonkai, который явно упоминается в первоначальном вопросе - он не удаляет запись в реестре, он просто удаляет ее. Актуальный вопрос, как удалить его из реестра
CupawnTae
1
Я бы просто добавил, что вам может понадобиться перезапустить / обновить cmd, прежде чем это вступит в силу.
Jiggunjer
@jiggunjer, как обновить?
Пейсер
@Pacerier просто откройте новый терминал.
jiggunjer
11

Команда в ответе DougWare не сработала, но это сработало:

reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v FOOBAR /f

Ярлык HKLMможет быть использован для HKEY_LOCAL_MACHINE.

user4297498
источник
1
Кроме того, переменные среды пользователя находятся в разделе "HKCU \ Environment"
tzrlk
1
@ Tzrlk, в чем причина несоответствия? Почему его нет в HKLM \ Environment?
Пейсер
@Pacerier: я понятия не имею, почему они помещают их в такие совершенно разные места, но если вы хотите убедиться, что вы удалили системные переменные или системные переменные, и / и пользовательские, полезно знать, что они совершенно разные мест.
tzrlk
2
@ Tzrlk, Должно быть, опять какая-то винтовая конструкция на стороне Windows.
Pacerier
4

Удалить без перезагрузки

На вопрос ОП действительно был получен исчерпывающий ответ, в том числе о том, как избежать перезагрузки с помощью powershell, vbscript или других имен.

Однако, если вам нужно придерживаться только команд cmd и вы не можете позволить себе вызывать powershell или vbscript, вы можете использовать следующий подход:

rem remove from current cmd instance
  SET FOOBAR=
rem remove from the registry if it's a user variable
  REG delete HKCU\Environment /F /V FOOBAR
rem remove from the registry if it's a system variable
  REG delete "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /F /V FOOBAR
rem tell Explorer.exe to reload the environment from the registry
  SETX DUMMY ""
rem remove the dummy
  REG delete HKCU\Environment /F /V DUMMY

Итак, магия здесь в том, что с помощью «setx» назначить что-то переменной, которая вам не нужна (в моем примере DUMMY), вы заставляете Explorer.exe перечитывать переменные из реестра, не используя powershell. Затем вы убираете этот манекен, и, хотя он будет оставаться в среде Explorer еще немного, он, вероятно, никому не повредит.

Или, если после удаления переменных вам нужно установить новые, вам даже не понадобится пустышка. Простое использование SETX для установки новых переменных автоматически удалит только что удаленные из любых новых задач cmd, которые могут начаться.

Справочная информация: я только что успешно использовал этот подход, чтобы заменить набор пользовательских переменных системными переменными с одинаковыми именами на всех компьютерах в моей работе, изменив существующий сценарий cmd. Слишком много компьютеров, чтобы сделать это вручную, и при этом было непрактично копировать дополнительные PowerShell или VBS-скрипты на все из них. Причина, по которой мне срочно потребовалось заменить пользователя системными переменными, заключалась в том, что пользовательские переменные синхронизировались в перемещаемых профилях (не задумываясь об этом), поэтому несколько машин, использующих один и тот же вход в Windows, но нуждающихся в разных значениях, перепутались.

Ронни Д'Хур
источник
3
setx FOOBAR ""

просто заставляет значение FOOBAR быть пустой строкой. (Хотя это показывается setкомандой с "", так что, возможно, двойные кавычки - это строка.)

Я использовал:

set FOOBAR=

и тогда FOOBAR больше не был указан в команде set. (Выход не требуется.)

Windows 7 32-разрядная, используя командную строку, не администратор это то, что я использовал. (Не cmd или Windows+ R, которые могут отличаться.)

Кстати, я не видел переменную, которую я создал где-то в реестре после того, как я ее создал. Я использую RegEdit не как администратор.

PReinie
источник
1

Вы также можете создать небольшой скрипт VBScript :

Set env = CreateObject("WScript.Shell").Environment("System")
If env(WScript.Arguments(0)) <> vbNullString Then env.Remove WScript.Arguments(0)

Тогда назови это как %windir%\System32\cscript.exe //Nologo "script_name.vbs" FOOBAR .

Недостаток в том, что вам нужен дополнительный скрипт, но он не требует перезагрузки.

Вернфрид Домшайт
источник