CMD中动态环境变量和普通环境变量的区别
Difference between Dynamic Environment Variables and Normal Environment Variables in CMD
我在 ss64 上阅读了一篇关于命令提示符中的环境变量的文章。
本文后面有一个 table,其中说明了命令提示符中常见的环境变量。其中列出的一些变量被称为 Volatile(只读)。文章中的一句话是这样写的:-
Dynamic environment variables are read-only and are computed each time the variable is expanded. When all variables are listed with SET, these will not appear in the list. Do not attempt to directly SET a dynamic variable.
后两句我明白了。但是第一个看不懂
疑惑:-
%userprofile%
是一个 非易失性 变量,解析为 %SystemDrive%\Users\{username}
,而 %homepath%
是一个 volatile 变量解析为 Users\{Username}
。这两个命令非常相似(systemdrive
除外)。那为什么一个是volatile,一个是non-volatile呢?
变量是动态的标准是什么?是什么让 %appdata%
(只是一个例子)成为一个非易失性变量?
每次扩展变量时都会计算动态变量,这对于 %CD% %DATE% %TIME% %RANDOM%
等变量很有意义,因为如果它们是 non,它们将失去其功能-挥发性。但是它会如何影响%homepath%
?
一些 非易失性 变量中有一些动态组件。前任。 %userprofile%
的路径中有 %SystemDrive%
和 {username}
。那这些变量怎么不是动态的呢?
使用命令 EnableDelayedExpansion
的选项 EnableDelayedExpansion
启用延迟环境变量扩展时,使用语法 %variable%
或 !variable!
访问三种类型的变量。 =28=] 来自 Windows 命令提示符 window 或批处理文件,即使用 %SystemRoot%\System32\cmd.exe
.
1。持久存储变量
环境 变量永久存储在 Windows 注册表中。
User 变量存储在 Windows 注册表项下:
HKEY_CURRENT_USER\Environment
System 变量存储在 Windows 注册表项下:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
user 变量仅针对存储它们的用户注册表配置单元(文件 %UserProfile%\ntuser.dat
)的帐户定义。 系统 变量是为 Windows 机器(文件 %SystemRoot%\System32\config\SYSTEM
)上使用的所有帐户定义的。
打开Windows 控制面板,点击系统,可以查看、编辑和删除持久存储变量,单击 高级系统设置 上的下一步(左侧),然后单击 环境变量 按钮。上半部分用于当前用户帐户的 user 变量,下半部分用于自 Windows XP 以来的 system 变量。
自 Windows XP 以来,默认定义为 user 变量 TEMP
和 TMP
。
预定义的列表系统变量是因为Windows XP:
ComSpec
NUMBER_OF_PROCESSORS
OS
PATH
PATHEXT
PROCESSOR_ARCHITECTURE
PROCESSOR_IDENTIFIER
PROCESSOR_LEVEL
PROCESSOR_REVISION
TEMP
TMP
windir
在 Windows Vista 和较新的 Windows 版本上默认定义了 系统 变量 PSModulePath
.
None 的预定义 system 变量(PATH
和 PATHEXT
除外)应该删除或修改,因为这可能会导致很多甚至可能导致 Windows 不再启动的问题。我强烈建议使用虚拟机来试验预定义的 system 变量,在开始试验之前存在整个虚拟机映像的备份。
1.1 持久存储变量的备份
建议在打开命令提示符 user 和 system 变量之前备份它们 window 和 运行 例如:
md C:\VariablesBackup 2>nul
%SystemRoot%\System32\reg.exe EXPORT HKCU\Environment "C:\VariablesBackup\UserVariables.reg"
%SystemRoot%\System32\reg.exe EXPORT "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "C:\VariablesBackup\SystemVariables.reg"
1.2 持久存储变量的恢复
恢复 user 变量可以在命令提示符下完成 window 在 之前使用以下命令进行备份:
%SystemRoot%\System32\reg.exe DELETE "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /f
%SystemRoot%\System32\reg.exe IMPORT "C:\VariablesBackup\UserVariables.reg"
恢复系统变量可以在命令提示符下完成window打开之前以管理员身份进行备份 与:
%SystemRoot%\System32\reg.exe DELETE HKCU\Environment /f
%SystemRoot%\System32\reg.exe IMPORT "C:\VariablesBackup\SystemVariables.reg"
建议从备份中恢复 user 和 system 变量后重新启动 Windows 以确保真正所有进程都使用恢复的变量。
1.3 使用批处理文件修改PATH
考虑使用批处理文件修改 user 或 system PATH
的批处理文件程序员应首先阅读:
- Why are other folder paths also added to system PATH with SetX and not only the specified folder path?
- How to search and replace a string in environment variable PATH?
- Adding the current directory to Windows path permanently
注意:绝对不行-永远不要使用命令SETX在批处理文件中使用 %PATH%
修改 user 或 system PATH
变量。
在安装程序(可执行或script) 是该程序主要供用户从 Windows 命令行使用。如果一个程序要求其目录或其子目录之一在 PATH
中才能工作,则该程序的设计很糟糕。如果程序将 system PATH
的文件夹路径添加到 Windows.
默认定义的文件夹路径,则该程序的设计非常糟糕
system PATH
变量应始终以:
开头
%SystemRoot%\System32;%SystemRoot%;%SystemRoot%\System32\Wbem
Windows系统目录是包含大多数可执行文件和动态链接库的目录。因此,它应该始终是在当前目录之后搜索可执行文件和库的第一个目录。
2。 Windows shell 变量
还有很多 Windows environment 预定义变量,可以在以下位置看到:
这些变量由 Windows shell 定义,默认情况下 explorer.exe
在 Windows 上启动 Windows shell 根据注册表项下的注册表值 Shell
:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
用户最注意的 Window shell 元素是 Windows 桌面、Windows 开始菜单和Windows 带有系统托盘的任务栏。
Windows shell 在其内存中定义了许多环境变量,这些变量取决于 Windows 注册表中的各种值,当前用户帐户未永久存储在 Windows 注册表中如上所述。每当创建新进程时都会复制当前的环境变量列表,例如从 Windows shell.
启动可执行文件
由Windowsshell定义的环境变量列表,由持久存储的user和system组成变量和当前用户帐户的 shell 变量可以通过打开命令提示符 window 和 运行 命令 SET 查看 没有任何附加参数。
大多数 shell 变量是根据
下的注册表字符串定义的
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
大多数注册表字符串值存在于 REG_EXPAND_SZ
类型的 User Shell Folders
和 REG_SZ
类型的 Shell Folders
中。但是有一些注册表字符串值仅存在于两个注册表项之一下。
另请参阅:
在这个答案中详细解释了 Windows Explorer 如何评估这些注册表字符串值并在用户使用 regedit.exe
或 reg.exe
对 shell 的示例进行手动修改时处理它们文件夹 Desktop
.
函数CreateEnvironmentBlock and the private shell32 function RegenerateUserEnvironment
are used by explorer.exe
with GetUserNameExW and GetComputerNameExW to create the environment variables list copied by Windows Explorer on starting an executable from Windows shell using the Windows kernel library function CreateProcess.
另见Eryk Sun on question Where are the environment variables for cmd.exe stored?
写的评论
64 位 Windows 上有一些环境变量取决于启动 64 位或 32 位可执行文件。 Microsoft 在 WOW64 Implementation Details 上将它们记录如下:
64-bit process:
PROCESSOR_ARCHITECTURE=AMD64 or PROCESSOR_ARCHITECTURE=IA64 or PROCESSOR_ARCHITECTURE=ARM64
ProgramFiles=%ProgramFiles%
ProgramW6432=%ProgramFiles%
CommonProgramFiles=%CommonProgramFiles%
CommonProgramW6432=%CommonProgramFiles%
Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: The ProgramW6432 and CommonProgramW6432 environment variables were added starting with Windows 7 and Windows Server 2008 R2.
32-bit process:
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=%PROCESSOR_ARCHITECTURE%
ProgramFiles=%ProgramFiles(x86)%
ProgramW6432=%ProgramFiles%
CommonProgramFiles=%CommonProgramFiles(x86)%
CommonProgramW6432=%CommonProgramFiles%
如果安装的 Windows 是 32 位的,则 environment 变量 PROCESSOR_ARCHITECTURE
的值不能用于从批处理文件中查找(x86) 或 64 位 (AMD64) Windows。该值取决于 64 位 %SystemRoot%\Sysem32\cmd.exe
或 32 位 %SystemRoot%\SysWOW64\cmd.exe
在 64 位 Windows.
上对批处理文件的处理
另请参阅 Microsoft 文档:
environment 变量的使用必须明智地编写由 Windows shell 定义的批处理文件,该批处理文件应设计为由其他人执行相同或不同 Windows 机器上的帐户。许多批处理文件在批处理文件作者的环境中运行良好,但由于 环境变量列表。
进程在使用Windows内核库函数启动可执行文件时定义的环境变量CreateProcess
决定了启动的可执行文件可以使用的环境变量。
大多数应用程序使用 CreateProcess
,参数 lpEnvironment
的值为 null
。因此 CreateProcess
复制当前进程的当前环境变量。出于这个原因,每个从 Windows 桌面、开始菜单或任务栏启动的可执行文件都会获得由 explorer.exe
实例 运行 定义为 Windows shell 的环境变量。
一个非常好的编码可执行文件或脚本,使用在 Windows 上默认定义的环境变量,明确验证每个使用的环境变量是否真正定义,否则使用合适的默认值,如 C:\Windows
环境变量 SystemRoot
未定义,检查是否确实存在目录 C:\Windows
,并退出并在可能造成损坏之前未定义的重要环境变量上显示适当的错误消息。
SystemRoot
是由 explorer.exe
定义的 Windows shell 变量作为环境变量的示例,它不是由 [=609] 的注册表字符串值确定的=] 文件夹。某些环境变量值不应由用户在任何时候独立于其真实来源进行修改,脚本作者永远不需要知道这些是 Windows 实现细节。
3。 Windows 命令处理器的动态变量
在命令提示符 window set /?
中 运行 输出的命令 SET 的帮助中列出了一些无法找到的变量在 运行 上的环境变量列表中只是 set
.
这些变量是:
CD
DATE
TIME
RANDOM
ERRORLEVEL
CMDEXTVERSION
CMDCMDLINE
HIGHESTNUMANODENUMBER
动态变量是cmd.exe
的内部变量。因此,这些变量仅在 Windows 命令提示符 window 中可用,它是 运行 cmd.exe
进程或由 cmd.exe
处理的批处理文件。 动态变量在其他可执行文件或脚本中不可用,因为这些变量不是环境变量。
最常用的动态变量是:
- CD
当前目录路径不以反斜线结尾,除了当前目录是驱动器的根目录。
[=384=日期
Windows. 的区域和语言设置中为帐户定义的格式的当前本地日期
- 时间
Windows. 的区域和语言设置中为帐户定义的格式的当前本地时间
- 错误级别
先前执行的命令或程序的退出值。
- 随机
0 到 32767 之间的随机十进制数。
还有一些动态变量,但很少在批处理文件中使用。
另外还有变量 __AppDir__
包含当前 运行 cmd.exe
的路径,总是以 Microsoft 未记录的反斜杠结尾。我建议不要使用这个 undocumented 变量,因为不能保证 cmd.exe
的未来版本仍然有这个变量。 __AppDir__
在 64 位上 Windows,例如,%SystemRoot%\System32\
在 64 位上 %SystemRoot%\System32\cmd.exe
当前 运行,或 %SystemRoot%\SysWOW64\
在 32 位上%SystemRoot%\SysWOW64\cmd.exe
当前 运行,或将 cmd.exe
复制到任何其他文件夹并启动此副本 cmd.exe
的任何其他路径。 SS64 页面 How-to: Windows Environment Variables 上列出了更多 未记录的动态 变量,出于同样的原因,在使用时应特别小心。
最常用的 动态 变量的值由 Windows 命令处理器本身动态更改,而环境变量的值仅在命令 [=285] 时更改=]SET 在执行批处理文件期间用于重新定义 environment 变量。这是 environment 和 dynamic 变量之间的重要区别。
4。访问动态变量的值
每个 environment 变量都可以在已处理批处理文件的 local 环境中删除或重新定义。没有 environment 变量 read-only.
cmd.exe
在其代码内部包含文件扩展名列表 .COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC
,如果 environment 变量 PATHEXT
,它用作 PATHEXT
的值 PATHEXT
不存在于 local 环境变量列表中,以便能够在命令行或批处理文件中找到没有文件扩展名的脚本和可执行文件。但是如果 environment 变量 PATH
在 local[=421= 中不存在,cmd.exe
不包含文件夹路径列表作为后备列表] 环境。因此,无论出于何种原因,批处理文件编写者在修改 本地环境 变量 PATH
时应该小心。
dynamic 变量的值被引用,就像 environment 变量的值被 %variable%
或 !variable!
启用 delayed expansion。但是 Windows 命令处理器总是首先在当前的 environment 变量列表中搜索是否存在具有指定名称的变量。仅当不存在具有该名称的 environment 变量时,cmd
在其内部动态变量列表中搜索下一个是否存在具有指定名称的变量。
dynamic 变量的当前值无法再在定义与 environment 变量同名的变量时被访问=]动态变量。因此,批处理文件编写器永远不应使用 dynamic 变量名称之一作为 environment 变量的名称。
这是一个代码,它演示了如果批处理文件编写者有一个非常糟糕的想法来定义名称为 ERRORLEVEL
.[=145 的 environment 变量会发生什么=]
@echo off
setlocal EnableExtensions DisableDelayedExpansion
echo/
echo Define environment variable ERRORLEVEL with string value "014".
echo/
set ERRORLEVEL=014
if %ERRORLEVEL% EQU 12 (echo EQU: ERRORLEVEL is 12.) else echo EQU: ERRORLEVEL is not 12.
if %ERRORLEVEL% == 014 (echo ==: ERRORLEVEL is 14.) else echo ==: ERRORLEVEL is not 14.
if errorlevel 0 (
if not errorlevel 1 (echo IF: ERRORLEVEL is 0.) else echo IF: ERRORLEVEL is greater than 0.
) else echo IF: ERRORLEVEL is less than 0.
echo/
echo Delete the environment variable ERRORLEVEL.
echo/
set ERRORLEVEL=
if %ERRORLEVEL% EQU 12 (echo EQU: ERRORLEVEL is 12.) else echo EQU: ERRORLEVEL is not 12.
if %ERRORLEVEL% == 014 (echo ==: ERRORLEVEL is 14.) else echo ==: ERRORLEVEL is not 14.
if errorlevel 0 (
if not errorlevel 1 (echo IF: ERRORLEVEL is 0.) else echo IF: ERRORLEVEL is greater than 0.
) else echo IF: ERRORLEVEL is less than 0.
echo/
echo In all test cases the value of dynamic variable ERRORLEVEL was 0.
echo/
for %%I in (%CMDCMDLINE%) do if /I "%%~I" == "/c" pause & goto EndBatch
:EndBatch
endlocal
这个批处理文件的输出是:
Define environment variable ERRORLEVEL with string value "014".
EQU: ERRORLEVEL is 12.
==: ERRORLEVEL is 14.
IF: ERRORLEVEL is 0.
Delete the environment variable ERRORLEVEL.
EQU: ERRORLEVEL is not 12.
==: ERRORLEVEL is not 14.
IF: ERRORLEVEL is 0.
In all test cases the value of dynamic variable ERRORLEVEL was 0.
可以看出 that the first IF condition if %ERRORLEVEL% EQU 12
results in replacing %ERRORLEVEL%
by the string 014
because of there is the environment variable ERRORLEVEL
defined with this string value. The function wcstol 被命令 IF 使用,因为运算符 EQU
将字符串 014
转换为被解释为八进制数因为前导 0
和字符串 12
到 32 位有符号整数值并比较它们是否相等。因此第一个条件为真。
第二个 IF 条件 if %ERRORLEVEL% == 014
也导致用字符串 014
替换 %ERRORLEVEL%
因为有 environment 变量 ERRORLEVEL
使用此字符串值定义。但是现在函数 lstrcmpW 被命令 IF 使用,因为运算符 ==
。所以第二个条件也成立。
第三个 IF 条件使用命令 IF 输出的帮助解释的推荐语法 运行 if /?
在命令提示符 window 中。可以看出,即使 environment 变量定义为名称 ERRORLEVEL
。评估先前执行的命令或程序的退出代码的推荐语法始终适用于批处理文件中的任何位置,如此处所示。
看到一个所以:
此外,必须考虑到访问 动态 变量的当前值总是在被 Windows 命令处理器扩展的变量引用上,而不是真正的执行命令或可执行文件。
证明差异的代码:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /L %%I in (1,1,3) do (
echo %%DATE%% %%TIME%% is: %DATE% %TIME%
echo ^^!DATA^^! ^^!TIME^^! is: !DATE! !TIME!
echo %%RANDOM%%/^^!RANDOM^^!: %RANDOM%/!RANDOM!
if exist %SystemRoot%\System32\timeout.exe (
%SystemRoot%\System32\timeout.exe /T 3 /NOBREAK >nul
) else (
%SystemRoot%\System32\ping.exe 127.0.0.1 -n 4 >nul
)
)
for %%I in (%CMDCMDLINE%) do if /I "%%~I" == "/c" pause & goto EndBatch
:EndBatch
endlocal
输出例如:
%DATE% %TIME% is: 31.01.2021 13:54:30,67
!DATA! !TIME! is: 31.01.2021 13:54:30,68
%RANDOM%/!RANDOM!: 18841/27537
%DATE% %TIME% is: 31.01.2021 13:54:30,67
!DATA! !TIME! is: 31.01.2021 13:54:33,12
%RANDOM%/!RANDOM!: 18841/16705
%DATE% %TIME% is: 31.01.2021 13:54:30,67
!DATA! !TIME! is: 31.01.2021 13:54:36,16
%RANDOM%/!RANDOM!: 18841/32668
%DATE% %TIME%
导致打印到控制台 window 三倍相同 date/time 因为这两个变量引用已经被 Windows 命令处理器在解析命令 FOR 之前的整个命令块都被执行了。 %RANDOM%
出于同样的原因导致打印三倍相同的数字,而 !RANDOM!
通常打印三个不同的数字。
另请参阅:
- How does the Windows Command Interpreter (CMD.EXE) parse scripts?
if errorlevel number
和 if not errorlevel number
也可以在命令方块中工作!
动态 环境变量只能在默认启用命令扩展的情况下访问。否则 Windows 命令处理器模拟 MS-DOS 和 Windows 的 COMMAND.COM
行为(或多或少) 95/98/ME 不支持 动态 正如这段代码所示:
@echo off
setlocal DisableExtensions DisableDelayedExpansion
echo/
echo With command extensions disabled:
echo/
echo Date/time is: %DATE% %TIME%
echo Current dir: "%CD%"
endlocal
setlocal EnableExtensions DisableDelayedExpansion
echo/
echo With command extensions enabled:
echo/
echo Date/time is: %DATE% %TIME%
echo Current dir: "%CD%"
echo/
for %%I in (%CMDCMDLINE%) do if /I "%%~I" == "/c" pause & goto EndBatch
:EndBatch
endlocal
输出例如:
With command extensions disabled:
Date/time is:
Current dir: ""
With command extensions enabled:
Date/time is: 31.01.2021 14:17:42,92
Current dir: "C:\Temp\Development & Test!"
动态变量的值只能读取。无法使用命令 SET 修改 dynamic 变量的值,因为它会导致定义 environment 变量具有 dynamic 变量的名称,该变量优先于 dynamic 变量。
我在 ss64 上阅读了一篇关于命令提示符中的环境变量的文章。
本文后面有一个 table,其中说明了命令提示符中常见的环境变量。其中列出的一些变量被称为 Volatile(只读)。文章中的一句话是这样写的:-
Dynamic environment variables are read-only and are computed each time the variable is expanded. When all variables are listed with SET, these will not appear in the list. Do not attempt to directly SET a dynamic variable.
后两句我明白了。但是第一个看不懂
疑惑:-
%userprofile%
是一个 非易失性 变量,解析为%SystemDrive%\Users\{username}
,而%homepath%
是一个 volatile 变量解析为Users\{Username}
。这两个命令非常相似(systemdrive
除外)。那为什么一个是volatile,一个是non-volatile呢?变量是动态的标准是什么?是什么让
%appdata%
(只是一个例子)成为一个非易失性变量?每次扩展变量时都会计算动态变量,这对于
%CD% %DATE% %TIME% %RANDOM%
等变量很有意义,因为如果它们是 non,它们将失去其功能-挥发性。但是它会如何影响%homepath%
?一些 非易失性 变量中有一些动态组件。前任。
%userprofile%
的路径中有%SystemDrive%
和{username}
。那这些变量怎么不是动态的呢?
使用命令 EnableDelayedExpansion
的选项 EnableDelayedExpansion
启用延迟环境变量扩展时,使用语法 %variable%
或 !variable!
访问三种类型的变量。 =28=] 来自 Windows 命令提示符 window 或批处理文件,即使用 %SystemRoot%\System32\cmd.exe
.
1。持久存储变量
环境 变量永久存储在 Windows 注册表中。
User 变量存储在 Windows 注册表项下:
HKEY_CURRENT_USER\Environment
System 变量存储在 Windows 注册表项下:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
user 变量仅针对存储它们的用户注册表配置单元(文件 %UserProfile%\ntuser.dat
)的帐户定义。 系统 变量是为 Windows 机器(文件 %SystemRoot%\System32\config\SYSTEM
)上使用的所有帐户定义的。
打开Windows 控制面板,点击系统,可以查看、编辑和删除持久存储变量,单击 高级系统设置 上的下一步(左侧),然后单击 环境变量 按钮。上半部分用于当前用户帐户的 user 变量,下半部分用于自 Windows XP 以来的 system 变量。
自 Windows XP 以来,默认定义为 user 变量 TEMP
和 TMP
。
预定义的列表系统变量是因为Windows XP:
ComSpec
NUMBER_OF_PROCESSORS
OS
PATH
PATHEXT
PROCESSOR_ARCHITECTURE
PROCESSOR_IDENTIFIER
PROCESSOR_LEVEL
PROCESSOR_REVISION
TEMP
TMP
windir
在 Windows Vista 和较新的 Windows 版本上默认定义了 系统 变量 PSModulePath
.
None 的预定义 system 变量(PATH
和 PATHEXT
除外)应该删除或修改,因为这可能会导致很多甚至可能导致 Windows 不再启动的问题。我强烈建议使用虚拟机来试验预定义的 system 变量,在开始试验之前存在整个虚拟机映像的备份。
1.1 持久存储变量的备份
建议在打开命令提示符 user 和 system 变量之前备份它们 window 和 运行 例如:
md C:\VariablesBackup 2>nul
%SystemRoot%\System32\reg.exe EXPORT HKCU\Environment "C:\VariablesBackup\UserVariables.reg"
%SystemRoot%\System32\reg.exe EXPORT "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "C:\VariablesBackup\SystemVariables.reg"
1.2 持久存储变量的恢复
恢复 user 变量可以在命令提示符下完成 window 在 之前使用以下命令进行备份:
%SystemRoot%\System32\reg.exe DELETE "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /f
%SystemRoot%\System32\reg.exe IMPORT "C:\VariablesBackup\UserVariables.reg"
恢复系统变量可以在命令提示符下完成window打开之前以管理员身份进行备份 与:
%SystemRoot%\System32\reg.exe DELETE HKCU\Environment /f
%SystemRoot%\System32\reg.exe IMPORT "C:\VariablesBackup\SystemVariables.reg"
建议从备份中恢复 user 和 system 变量后重新启动 Windows 以确保真正所有进程都使用恢复的变量。
1.3 使用批处理文件修改PATH
考虑使用批处理文件修改 user 或 system PATH
的批处理文件程序员应首先阅读:
- Why are other folder paths also added to system PATH with SetX and not only the specified folder path?
- How to search and replace a string in environment variable PATH?
- Adding the current directory to Windows path permanently
注意:绝对不行-永远不要使用命令SETX在批处理文件中使用 %PATH%
修改 user 或 system PATH
变量。
在安装程序(可执行或script) 是该程序主要供用户从 Windows 命令行使用。如果一个程序要求其目录或其子目录之一在 PATH
中才能工作,则该程序的设计很糟糕。如果程序将 system PATH
的文件夹路径添加到 Windows.
system PATH
变量应始终以:
%SystemRoot%\System32;%SystemRoot%;%SystemRoot%\System32\Wbem
Windows系统目录是包含大多数可执行文件和动态链接库的目录。因此,它应该始终是在当前目录之后搜索可执行文件和库的第一个目录。
2。 Windows shell 变量
还有很多 Windows environment 预定义变量,可以在以下位置看到:
这些变量由 Windows shell 定义,默认情况下 explorer.exe
在 Windows 上启动 Windows shell 根据注册表项下的注册表值 Shell
:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
用户最注意的 Window shell 元素是 Windows 桌面、Windows 开始菜单和Windows 带有系统托盘的任务栏。
Windows shell 在其内存中定义了许多环境变量,这些变量取决于 Windows 注册表中的各种值,当前用户帐户未永久存储在 Windows 注册表中如上所述。每当创建新进程时都会复制当前的环境变量列表,例如从 Windows shell.
启动可执行文件由Windowsshell定义的环境变量列表,由持久存储的user和system组成变量和当前用户帐户的 shell 变量可以通过打开命令提示符 window 和 运行 命令 SET 查看 没有任何附加参数。
大多数 shell 变量是根据
下的注册表字符串定义的HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
大多数注册表字符串值存在于 REG_EXPAND_SZ
类型的 User Shell Folders
和 REG_SZ
类型的 Shell Folders
中。但是有一些注册表字符串值仅存在于两个注册表项之一下。
另请参阅:
在这个答案中详细解释了 Windows Explorer 如何评估这些注册表字符串值并在用户使用 regedit.exe
或 reg.exe
对 shell 的示例进行手动修改时处理它们文件夹 Desktop
.
函数CreateEnvironmentBlock and the private shell32 function RegenerateUserEnvironment
are used by explorer.exe
with GetUserNameExW and GetComputerNameExW to create the environment variables list copied by Windows Explorer on starting an executable from Windows shell using the Windows kernel library function CreateProcess.
另见Eryk Sun on question Where are the environment variables for cmd.exe stored?
写的评论64 位 Windows 上有一些环境变量取决于启动 64 位或 32 位可执行文件。 Microsoft 在 WOW64 Implementation Details 上将它们记录如下:
64-bit process:
PROCESSOR_ARCHITECTURE=AMD64 or PROCESSOR_ARCHITECTURE=IA64 or PROCESSOR_ARCHITECTURE=ARM64
ProgramFiles=%ProgramFiles%
ProgramW6432=%ProgramFiles%
CommonProgramFiles=%CommonProgramFiles%
CommonProgramW6432=%CommonProgramFiles%Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: The ProgramW6432 and CommonProgramW6432 environment variables were added starting with Windows 7 and Windows Server 2008 R2.
32-bit process:
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=%PROCESSOR_ARCHITECTURE%
ProgramFiles=%ProgramFiles(x86)%
ProgramW6432=%ProgramFiles%
CommonProgramFiles=%CommonProgramFiles(x86)%
CommonProgramW6432=%CommonProgramFiles%
如果安装的 Windows 是 32 位的,则 environment 变量 PROCESSOR_ARCHITECTURE
的值不能用于从批处理文件中查找(x86) 或 64 位 (AMD64) Windows。该值取决于 64 位 %SystemRoot%\Sysem32\cmd.exe
或 32 位 %SystemRoot%\SysWOW64\cmd.exe
在 64 位 Windows.
另请参阅 Microsoft 文档:
environment 变量的使用必须明智地编写由 Windows shell 定义的批处理文件,该批处理文件应设计为由其他人执行相同或不同 Windows 机器上的帐户。许多批处理文件在批处理文件作者的环境中运行良好,但由于 环境变量列表。
进程在使用Windows内核库函数启动可执行文件时定义的环境变量CreateProcess
决定了启动的可执行文件可以使用的环境变量。
大多数应用程序使用 CreateProcess
,参数 lpEnvironment
的值为 null
。因此 CreateProcess
复制当前进程的当前环境变量。出于这个原因,每个从 Windows 桌面、开始菜单或任务栏启动的可执行文件都会获得由 explorer.exe
实例 运行 定义为 Windows shell 的环境变量。
一个非常好的编码可执行文件或脚本,使用在 Windows 上默认定义的环境变量,明确验证每个使用的环境变量是否真正定义,否则使用合适的默认值,如 C:\Windows
环境变量 SystemRoot
未定义,检查是否确实存在目录 C:\Windows
,并退出并在可能造成损坏之前未定义的重要环境变量上显示适当的错误消息。
SystemRoot
是由 explorer.exe
定义的 Windows shell 变量作为环境变量的示例,它不是由 [=609] 的注册表字符串值确定的=] 文件夹。某些环境变量值不应由用户在任何时候独立于其真实来源进行修改,脚本作者永远不需要知道这些是 Windows 实现细节。
3。 Windows 命令处理器的动态变量
在命令提示符 window set /?
中 运行 输出的命令 SET 的帮助中列出了一些无法找到的变量在 运行 上的环境变量列表中只是 set
.
这些变量是:
CD
DATE
TIME
RANDOM
ERRORLEVEL
CMDEXTVERSION
CMDCMDLINE
HIGHESTNUMANODENUMBER
动态变量是cmd.exe
的内部变量。因此,这些变量仅在 Windows 命令提示符 window 中可用,它是 运行 cmd.exe
进程或由 cmd.exe
处理的批处理文件。 动态变量在其他可执行文件或脚本中不可用,因为这些变量不是环境变量。
最常用的动态变量是:
- CD
当前目录路径不以反斜线结尾,除了当前目录是驱动器的根目录。
[=384=日期 - 时间
Windows. 的区域和语言设置中为帐户定义的格式的当前本地时间
- 错误级别
先前执行的命令或程序的退出值。 - 随机
0 到 32767 之间的随机十进制数。
Windows. 的区域和语言设置中为帐户定义的格式的当前本地日期
还有一些动态变量,但很少在批处理文件中使用。
另外还有变量 __AppDir__
包含当前 运行 cmd.exe
的路径,总是以 Microsoft 未记录的反斜杠结尾。我建议不要使用这个 undocumented 变量,因为不能保证 cmd.exe
的未来版本仍然有这个变量。 __AppDir__
在 64 位上 Windows,例如,%SystemRoot%\System32\
在 64 位上 %SystemRoot%\System32\cmd.exe
当前 运行,或 %SystemRoot%\SysWOW64\
在 32 位上%SystemRoot%\SysWOW64\cmd.exe
当前 运行,或将 cmd.exe
复制到任何其他文件夹并启动此副本 cmd.exe
的任何其他路径。 SS64 页面 How-to: Windows Environment Variables 上列出了更多 未记录的动态 变量,出于同样的原因,在使用时应特别小心。
最常用的 动态 变量的值由 Windows 命令处理器本身动态更改,而环境变量的值仅在命令 [=285] 时更改=]SET 在执行批处理文件期间用于重新定义 environment 变量。这是 environment 和 dynamic 变量之间的重要区别。
4。访问动态变量的值
每个 environment 变量都可以在已处理批处理文件的 local 环境中删除或重新定义。没有 environment 变量 read-only.
cmd.exe
在其代码内部包含文件扩展名列表 .COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC
,如果 environment 变量 PATHEXT
,它用作 PATHEXT
的值 PATHEXT
不存在于 local 环境变量列表中,以便能够在命令行或批处理文件中找到没有文件扩展名的脚本和可执行文件。但是如果 environment 变量 PATH
在 local[=421= 中不存在,cmd.exe
不包含文件夹路径列表作为后备列表] 环境。因此,无论出于何种原因,批处理文件编写者在修改 本地环境 变量 PATH
时应该小心。
dynamic 变量的值被引用,就像 environment 变量的值被 %variable%
或 !variable!
启用 delayed expansion。但是 Windows 命令处理器总是首先在当前的 environment 变量列表中搜索是否存在具有指定名称的变量。仅当不存在具有该名称的 environment 变量时,cmd
在其内部动态变量列表中搜索下一个是否存在具有指定名称的变量。
dynamic 变量的当前值无法再在定义与 environment 变量同名的变量时被访问=]动态变量。因此,批处理文件编写器永远不应使用 dynamic 变量名称之一作为 environment 变量的名称。
这是一个代码,它演示了如果批处理文件编写者有一个非常糟糕的想法来定义名称为 ERRORLEVEL
.[=145 的 environment 变量会发生什么=]
@echo off
setlocal EnableExtensions DisableDelayedExpansion
echo/
echo Define environment variable ERRORLEVEL with string value "014".
echo/
set ERRORLEVEL=014
if %ERRORLEVEL% EQU 12 (echo EQU: ERRORLEVEL is 12.) else echo EQU: ERRORLEVEL is not 12.
if %ERRORLEVEL% == 014 (echo ==: ERRORLEVEL is 14.) else echo ==: ERRORLEVEL is not 14.
if errorlevel 0 (
if not errorlevel 1 (echo IF: ERRORLEVEL is 0.) else echo IF: ERRORLEVEL is greater than 0.
) else echo IF: ERRORLEVEL is less than 0.
echo/
echo Delete the environment variable ERRORLEVEL.
echo/
set ERRORLEVEL=
if %ERRORLEVEL% EQU 12 (echo EQU: ERRORLEVEL is 12.) else echo EQU: ERRORLEVEL is not 12.
if %ERRORLEVEL% == 014 (echo ==: ERRORLEVEL is 14.) else echo ==: ERRORLEVEL is not 14.
if errorlevel 0 (
if not errorlevel 1 (echo IF: ERRORLEVEL is 0.) else echo IF: ERRORLEVEL is greater than 0.
) else echo IF: ERRORLEVEL is less than 0.
echo/
echo In all test cases the value of dynamic variable ERRORLEVEL was 0.
echo/
for %%I in (%CMDCMDLINE%) do if /I "%%~I" == "/c" pause & goto EndBatch
:EndBatch
endlocal
这个批处理文件的输出是:
Define environment variable ERRORLEVEL with string value "014".
EQU: ERRORLEVEL is 12.
==: ERRORLEVEL is 14.
IF: ERRORLEVEL is 0.
Delete the environment variable ERRORLEVEL.
EQU: ERRORLEVEL is not 12.
==: ERRORLEVEL is not 14.
IF: ERRORLEVEL is 0.
In all test cases the value of dynamic variable ERRORLEVEL was 0.
可以看出 if %ERRORLEVEL% EQU 12
results in replacing %ERRORLEVEL%
by the string 014
because of there is the environment variable ERRORLEVEL
defined with this string value. The function wcstol 被命令 IF 使用,因为运算符 EQU
将字符串 014
转换为被解释为八进制数因为前导 0
和字符串 12
到 32 位有符号整数值并比较它们是否相等。因此第一个条件为真。
第二个 IF 条件 if %ERRORLEVEL% == 014
也导致用字符串 014
替换 %ERRORLEVEL%
因为有 environment 变量 ERRORLEVEL
使用此字符串值定义。但是现在函数 lstrcmpW 被命令 IF 使用,因为运算符 ==
。所以第二个条件也成立。
第三个 IF 条件使用命令 IF 输出的帮助解释的推荐语法 运行 if /?
在命令提示符 window 中。可以看出,即使 environment 变量定义为名称 ERRORLEVEL
。评估先前执行的命令或程序的退出代码的推荐语法始终适用于批处理文件中的任何位置,如此处所示。
看到一个所以:
此外,必须考虑到访问 动态 变量的当前值总是在被 Windows 命令处理器扩展的变量引用上,而不是真正的执行命令或可执行文件。
证明差异的代码:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /L %%I in (1,1,3) do (
echo %%DATE%% %%TIME%% is: %DATE% %TIME%
echo ^^!DATA^^! ^^!TIME^^! is: !DATE! !TIME!
echo %%RANDOM%%/^^!RANDOM^^!: %RANDOM%/!RANDOM!
if exist %SystemRoot%\System32\timeout.exe (
%SystemRoot%\System32\timeout.exe /T 3 /NOBREAK >nul
) else (
%SystemRoot%\System32\ping.exe 127.0.0.1 -n 4 >nul
)
)
for %%I in (%CMDCMDLINE%) do if /I "%%~I" == "/c" pause & goto EndBatch
:EndBatch
endlocal
输出例如:
%DATE% %TIME% is: 31.01.2021 13:54:30,67
!DATA! !TIME! is: 31.01.2021 13:54:30,68
%RANDOM%/!RANDOM!: 18841/27537
%DATE% %TIME% is: 31.01.2021 13:54:30,67
!DATA! !TIME! is: 31.01.2021 13:54:33,12
%RANDOM%/!RANDOM!: 18841/16705
%DATE% %TIME% is: 31.01.2021 13:54:30,67
!DATA! !TIME! is: 31.01.2021 13:54:36,16
%RANDOM%/!RANDOM!: 18841/32668
%DATE% %TIME%
导致打印到控制台 window 三倍相同 date/time 因为这两个变量引用已经被 Windows 命令处理器在解析命令 FOR 之前的整个命令块都被执行了。 %RANDOM%
出于同样的原因导致打印三倍相同的数字,而 !RANDOM!
通常打印三个不同的数字。
另请参阅:
- How does the Windows Command Interpreter (CMD.EXE) parse scripts?
if errorlevel number
和 if not errorlevel number
也可以在命令方块中工作!
动态 环境变量只能在默认启用命令扩展的情况下访问。否则 Windows 命令处理器模拟 MS-DOS 和 Windows 的 COMMAND.COM
行为(或多或少) 95/98/ME 不支持 动态 正如这段代码所示:
@echo off
setlocal DisableExtensions DisableDelayedExpansion
echo/
echo With command extensions disabled:
echo/
echo Date/time is: %DATE% %TIME%
echo Current dir: "%CD%"
endlocal
setlocal EnableExtensions DisableDelayedExpansion
echo/
echo With command extensions enabled:
echo/
echo Date/time is: %DATE% %TIME%
echo Current dir: "%CD%"
echo/
for %%I in (%CMDCMDLINE%) do if /I "%%~I" == "/c" pause & goto EndBatch
:EndBatch
endlocal
输出例如:
With command extensions disabled:
Date/time is:
Current dir: ""
With command extensions enabled:
Date/time is: 31.01.2021 14:17:42,92
Current dir: "C:\Temp\Development & Test!"
动态变量的值只能读取。无法使用命令 SET 修改 dynamic 变量的值,因为它会导致定义 environment 变量具有 dynamic 变量的名称,该变量优先于 dynamic 变量。