對於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。
-- from Environment Variables in Windows XP
意譯一下:
環境變數是一組特殊的變數(這裡別名/標誌符我就直接譯為變數了)
它們儲存了一些系統的基本屬性
這些屬性一般用來為程式或系統管理員提供便利
環境變數裡面儲存的一般是一些路徑,檔案名稱,系統參數值等資訊
當程式需要這些值時,就可去問詢環境變數
環境變數既然能夠為程式提供資訊,就可以影響程式的行為
比如開始的例子裡,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
各項因子按照何種順序和規則得到最終環境變數?
MS的文檔中對此有過解釋
Variables are processed in the following order:
- 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.
NOTE: If the same variable is defined more than once, the value of the variable is the value that is set last.
——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.