对于path这个环境变量,我们是用的最多的,这里以此为例:
假如我们在cmd中输入一个link.exe,系统是如何找到正确的link.exe执行的?
这个问题我一直想找到精确的答案,目前却只获取到整个链条中的几段。
下面描述我试图一窥全貌的过程,希望大家能补充缺失的环节,使这条链子串起来。
+ 所知片段1
找寻的第一步——先在当前目录下找(这步应该没错,我可以确信)
如果在当前目录下找到了link.exe,那么直接执行这个可执行文件,无需再继续找寻。
+ 所知片段2
如果在当前目录下没有找到,系统会去一种叫环境变量的地方找寻path这个变量,进而从中获取一些路径。
拿到这些路径,系统会按照某种顺序,从这些地方挨个查找link.exe:
找到就马上执行之,不再继续查找;否则继续往下找,直至找完所有路径。
问题来了:
- 疑问1. 什么是环境变量?
- 疑问2. 环境变量里的值从哪里来?最终提供给程序的值是如何确定的?
- 疑问3. 对于获取到“一些路径”,系统将按照何种顺序依次进行找寻?
+ 所知片段3 (答疑问1)
什么是环境变量?
Environment variables are specially named aliases or placeholders for certain basic system properties that are present for convenience in programming and in system administration。
意译一下:
环境变量是一组特殊的变量(这里别名/标志符我就直接译为变量了)
它们保存了一些系统的基本属性
这些属性一般用来为程序或系统管理员提供便利
环境变量里面存储的一般是一些路径,文件名,系统参数值等信息
当程序需要这些值时,就可去问询环境变量
环境变量既然能够为程序提供信息,就可以影响程序的行为
比如开始的例子里,command程序执行link.exe,若本目录下未找到link.exe,它接下来的行为就受到了环境变量的影响
一个约定:
为了和下面可能讨论到的其他环境变量相区别,我们把这里所谓的“可影响程序行为的环境变量”称为“最终环境变量”.
后文形形色色的其他也叫“环境变量”的东西,我们姑且认为是“影响最终环境变量”的参数。
程序运行时,如何得知当前程序可利用哪些环境变量?这些变量里的值是什么?
对于一般的程序,应该有相应的API可获取这些值,我不太清楚,这里做个记号以后补上。【mark】
对于批处理程序,可以通过windows提供的set工具来输出此时作用这个批处理程序的所有环境变量以及其中的值。
例如:
-------------
【mark】这里待补充一个例子
---------------
+ 所知片段4 (答疑问2)
好了,到此为止,我们知道了什么是环境变量,以及如何窥见这些变量最终被程序使用的值。
但这些变量以及这些变量的值是从哪里来的呢?最终的值又是如何确定的呢?
可影响最终环境变量及其值的各项因子
根据查看MS的文档结合网上其他资料,我总结了一下,在windowsXP 中,可能影响最终环境变量的,一共有5处:
- system hidden-variables 系统预设动态环境变量
- system-variables 系统环境变量 (Admin可通过系统的环境变量对话框进行设置)
- system autoexec-variables 启动环境变量 (系统启动时读取autoexec.bat设置的环境变量)
- current user-variables 当前用户环境变量 (当前用户可通过系统的环境变量对话框进行设置)
- program set-variables 当前程序内设环境变量 (当前程序/批处理通过set设置的环境变量)
注:其实在这5种之外,还有一类“系统根据运行时状态自动扩展的动态环境变量”(见文末【补充1】)
但由于它们和最终环境变量没有交集,并不会对最终环境变量造成影响,所以这里不予列出
下面具体介绍一下这5种环境变量:
- 1. system hidden-variables 系统预设动态环境变量
网上并没有找到这种环境变量的完整定义和解释。
MS 文档中提到过“default system variables”和“Dynamic variables”的概念
我姑且就起这样一个名字
既然MS都没有明确的定义,为什么我要单独列出这么一种环境变量,并且往MS文档上“攀亲戚”呢?
因为我在用set查看最终的环境变量时,发现了这么几项比较“特殊”的环境变量:
ALLUSERSPROFILE=C:/Documents and Settings/All Users
APPDATA=G:/myProfile/Application Data
CommonProgramFiles=C:/Program Files/Common Files
COMPUTERNAME=MYNAME
HOMEDRIVE=C:
HOMEPATH=/Documents and Settings/mynick
LOGONSERVER=//MYNAME
ProgramFiles=C:/Program Files
PROMPT=$P$G
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:/WINDOWS
USERDOMAIN=MYNAME
USERNAME=mynick
它们有何“特殊”?
原来,在“我的电脑-属性-高级-环境变量”里,无论是系统变量还是用户变量里,都找不到这些值。
既然找不到,我怀疑它们和那些能在设置界面看得到的环境变量有所不同,可能存放在不同的地方。
(后来发现的确存放在不同地方,见文末【补充2】)
从内容上来看,认为是在系统初始化过程中从系统一些特殊的地方读取来信息从而设置的。
(到底是什么阶段,从哪里获取得到这些信息,这里尚不确定)【mark】
根据以上事实,我将它们专门划分为一类。
- 2. system-variables 系统环境变量
不过管理员可以在“系统属性-高级-环境变量-系统变量”中去修改它们。
- 3. system autoexec-variables 启动环境变量
系统在启动过程中,可分析autoexec.bat中的set语句对环境变量进行设置。
事实上,很多资料(资料1,资料2)在解释环境变量作用顺序的时候,都提到了这种方式设置的环境变量
但大部分资料都没有讲清楚下面这个事实:
“ 在2000/XP/2003等NT系统中,(windows的)启动过程不再依赖于config.sys/autoexec.bat这两个文件。其中,对 于 config.sys 已完全不再使用,对于 autoexec.bat ,只有在注册表(见引用)中的 ParseAutoexec 值为1(默认即为此值)时,才会分析其中的 set / path 等环境变量设置语句,其它语句任何情况下均会被忽略。"
Quote:
User Key: [HKEY_CURRENT_USER/Software/Microsoft/Windows NT/CurrentVersion/Winlogon]
Value Name: ParseAutoexec
Data Type: REG_SZ (String Value)
Value Data: (0 = disabled, 1 = enabled)
——from cn-dos的这个帖子, by 荣誉版主willsort
- 4. current user-variables 当前用户环境变量
当前用户可以在“系统属性-高级-环境变量-系统变量”中进行设置。
- 5. program set-variables 当前程序内设环境变量
在批处理内,可以通过set命令来给当前进程设置内部环境变量。
set命令的格式和用法,参见:SET
各项因子按照何种顺序和规则得到最终环境变量?
Variables are processed in the following order:
NOTE: If the same variable is defined more than once, the value of the variable is the value that is set last.
- Dynamic variables such as operating system variables.
- System variables defined in the System tool in Control Panel.
- Variables defined in the Autoexec.bat file.
- Environment variables defined in the System tool in Control panel for the current user.
——Environment Variable Processing Order in Windows 2000 , Q185652
不过文档里注明,本文档适用于“Windows 2000 Server & Microsoft Windows 2000 Professional Edition”
不知道WindowsXP里是否也适用于这一流程和特性。待验证!【mark】
这里姑且按照MS文档的流程来理解:
事实上,正好按照上面介绍的5个因子的顺序:
- hidden-variables
- system-variables
- autoexec-variables
- user-variables
- set-variables
自上而下,依次从这些变量里拿出 key-value 作为最终环境变量
如果某个key-value在这些因子中定义了超过一次
则以最后一个定义的key-value为准
我们称其为覆盖规则
【更新】这里目前发现一个例外的追加规则
user-variables 中若定义了path
则这个 path 不会覆盖 system-variables 中定义的值
而是会将路径添加在其后
举例说明:
若system-variables中,path设置为 "C:/folderA;C:/folderB"
而user-variables中,又将path设置为 "C:/folderC"
如果接下来没有设置set-variables
那么最终的环境变量中,path就是 "C:/folderA;C:/folderB;C:/folderC"
当然,如果接下来在set-variable这步用set重写了path
那么根据覆盖规则,最终的path仍是以set的path为准
+ 所知片段5 (答疑问3)
上面我们已经知道了最终的环境变量的值是如何来的
用例子来讲,我们现在已经知道了,一旦当前目录没发现link.exe,就会去找环境变量path
我们也知道了path里的值是怎么来的
接下来,有了这组路径,按照什么顺序查找路径呢?
从左往右,还是从右往左呢?
答案是从左往右
+ 所知片段6
同名不同扩展名,执行哪个?
事实上,例子里由于是明确的说要找link.exe
假如是在cmd里输入link,不加扩展名,系统在获取到path之后,怎么进行查找呢??
答案是根据环境变量"PATHEXT"中的值来确定以什么顺序找哪些扩展名。
比如"PATHEXT"中的值为:
.COM;.EXE;.BAT;.CMD
那么如果该目录下有link.COM link.EXE link.BAT link.CMD
在命令行输入link,执行的肯定是link.COM
OVER!
===================================================
【补充1】
下面几个是根据当前系统或程序的状态,动态扩展的环境变量。
%CD% - 扩展到当前目录字符串。
%DATE% - 用跟 DATE 命令同样的格式扩展到当前日期。
%TIME% - 用跟 TIME 命令同样的格式扩展到当前时间。
%RANDOM% - 扩展到 0 和 32767 之间的任意十进制数字。
%ERRORLEVEL% - 扩展到当前 ERRORLEVEL 数值。
%CMDEXTVERSION% - 扩展到当前命令处理器扩展名版本号。
%CMDCMDLINE% - 扩展到调用命令处理器的原始命令行。
---------------------------------------------------------------------
【补充2】
注册表中的环境变量
关于 看得到的系统环境变量和用户环境变量 和 看不见到却有系统默认值的环境变量
上文对这两种变量的来源做过一点猜测,认为它们“可能存放在不同的地方”。
经过对注册表的排查,我发现——
那些看得到的system variables,全部在注册表此处:
[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/Environment]
(内容略)
那些看得到的currentUser variables,全部在注册表的此处:
[HKEY_CURRENT_USER/Environment]
(内容略)
而那些初始情况下有默认值,看不到的default system variables,并未在注册表中找到集中的描述:
最大规模的是这个键
[HKEY_CURRENT_USER/Volatile Environment]
"LOGONSERVER"="MYNAME"
"CLIENTNAME"=""
"SESSIONNAME"="Console"
"APPDATA"="G://myProfile//Application Data"
"HOMEDRIVE"="C:"
"HOMESHARE"=""
"HOMEPATH"="//Documents and Settings//mynick"
[HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Control/ComputerName/ComputerName]
"ComputerName"="MYNAME"
鉴于这一伙都是和用户关联的变量,我认为它们是选择某个用户登录时,才同时写入注册表和环境变量的
其他几个没在注册表里找到的:
USERDOMAIN
这个是用户设定的计算机名,猜测是系统安装时确定下来了的
SystemDrive
猜测是系统安装时确定下来的
SystemRoot
这个是系统类型决定的值,windowsXP 就是 %SystemDrive%/WINDOWS
PROMPT
怀疑是系统预设死为$P$G(指cmd中默认使用current_drive_and_path>这种形式,参见 PROMPT )
ALLUSERSPROFILE
注册表中无精确匹配项,但有如下可组合项:
[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/ProfileList]
"ProfilesDirectory"="%SystemDrive%/Documents and Settings"
"DefaultUserProfile"="Default User"
"AllUsersProfile"="All Users"
关于default system variables,MS有这样的描述
During installation, Windows XP Setup configures the default system variables, such as the path to the Windows files.
-- How To Manage Environment Variables in Windows XP , MS Q310519
我认为后面几个未在注册表中找到的变量,就是依此所言,是WindowXP在安装初始化时就已经确定下来了。
【补充3】
在系统的环境变量对话框中,修改了系统变量或用户变量后,什么时候起作用?
很多资料说要重启系统,有的说重开一个cmd就行了
我验证了一下,发现:
所有对环境变量的修改,对原来开的那个cmd进程都无效果。
但只要重开一个cmd,就能看到修改的效果了
------------------------------------------------------------
Powered by ScribeFire.
