为什么我不能在 Windows 7 上访问名为 __CD__ 的变量? [英] Why can't I access a variable named __CD__ on Windows 7?

查看:31
本文介绍了为什么我不能在 Windows 7 上访问名为 __CD__ 的变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意 - 此问题基于在 Windows 7 上观察到的行为.我相信该行为适用于从 Vista 开始的所有其他版本.根据 MC ND 的回答和 Foxidrive 的评论,它不适用于 XP.

我可以使用伪动态变量 %CD% 来获取当前目录,而无需尾随 .如果我使用 set "CD=someValue" 定义一个名为 CD 的真正变量,则 %CD% 返回我分配的值,而不是当前目录.

I can use the pseudo dynamic variable %CD% to get the current directory, without a trailing . If I define a true variable named CD using set "CD=someValue", then %CD% returns the value I assigned, and not the current directory.

一个鲜为人知的动态变量是 %__CD__%,它与 %CD% 相同,只是它包含尾随 .但是如果我set "__CD__=someValue",我就无法访问我分配的值!我可以使用 set __CD__ 来查看我的变量是否存在我的赋值,但 %__CD__% 总是返回当前目录!

A lesser known dynamic variable is %__CD__%, which is the same as %CD%, except it includes the trailing . But if I do set "__CD__=someValue", I cannot access my assigned value! I can use set __CD__ to see that my variable exists with my assigned value, but %__CD__% always returns the current directory!

有谁知道这个 %__CD__% 机制是如何工作的(为什么它不同于任何其他动态变量)?

Does anyone have any idea how this %__CD__% mechanism works (why it is different than any other dynamic variable)?

谁能想出一种方法来访问我的 __CD__ 变量,只使用标准批处理命令(不解析 set __CD__ 的输出)?

Can someone come up with a way to access my __CD__ variable using nothing but standard batch commands (without parsing the output of set __CD__)?

这更多是一个学术问题,而不是一个实际问题.任何人都不应该使用与动态变量匹配的名称来定义变量.

This is more an academic question, not a practical one. No one should be defining variables with names that match dynamic variables.

我不想要一个解析 set __CD__ 结果的例程的原因是因为值中可以有换行符.有人可以定义两个变量,__CD____CD__2,或者他们可以定义一个 __CD__ 值,其值包含换行符后跟 __CD__2=....不可能区分这两种情况.(正如我所说,这是一个学术问题,而不是实际问题!)

The reason I do not want a routine that parses the results of set __CD__ is because values can have line feeds in them. Someone could define two variables, __CD__ and __CD__2, or they could define a single __CD__ value with a value containing a line feed followed by __CD__2=.... It would be impossible to differentiate between those two scenarios. (As I said, this is an academic question, not a practical one!)

推荐答案

我对 __CD__ 的行为方式和原因与其他任何伪环境变量有何不同有一个理论.

I have a theory as to how and why __CD__ behaves so differently than any of the other pseudo environment variable.

我写了一个简单的 ENV.JS 脚本来探测进程环境.

I wrote a simple ENV.JS script to probe the process environment.

var env=WScript.CreateObject("WScript.Shell").Environment("Process");
WScript.echo(env(WScript.Arguments.Item(0)));

ENV.JS 需要一个环境变量名作为唯一的参数,并简单地打印变量的值.我在 Windows 7 机器上进行了测试.该脚本可以在 CMD.EXE 控制台中运行,也可以通过定义参数的快捷方式直接运行.

ENV.JS expects an environment variable name as the one and only argument, and simply prints the value of the variable. I did my testing on a Windows 7 machine. The script can be run from within a CMD.EXE console, or it can be run directly via a shortcut that defines the argument.

我将对各种动态变量进行分类,展示不同的行为,以及关于它们工作机制的理论.

I will classify the various dynamic variables, showing contrasting behaviors, along with a theory as to the mechanism by which they work.

有许多动态变量可以分为三类:

There are a number of dynamic variables that can be divided into three classes:

1) 没有任何前缀或后缀的普通变量"

CD              current directory
DATE            current date
TIME            current time
ERRORLEVEL      current errorlevel
RANDOM          random integer between 0 and 32767
CMDEXTVERSION   current extension level (only available if extensions are enabled)
CMDCMDLINE      the command line that invoked the current CMD.EXE level

动态值只能通过 CMD.EXE 中的扩展获得,并且只有在启用命令扩展时才可用.它们不能通过 SET 或 ENV.JS 获得.可以通过使用 SET 显式定义静态值来覆盖动态值.覆盖值可通过 SET 和 ENV.JS 获得.

The dynamic values are only available via expansion within CMD.EXE, and only when command extensions are enabled. They are not available via SET, or by ENV.JS. The dynamic values can be overridden by explicitly defining a static value using SET. The override values are available via SET and ENV.JS.

C:	est>echo %cmdcmdline%
"C:Windowssystem32cmd.exe"

C:	est>set cmdcmdline
Environment variable cmdcmdline not defined

C:	est>cscript //nologo env.js cmdcmdline
cmdcmdline=

C:	est>set cmdcmdline=override

C:	est>echo %cmdcmdline%
override

C:	est>set cmdcmdline
cmdcmdline=override

C:	est>cscript //nologo env.js cmdcmdline
cmdcmdline=override

C:	est>cmd /e:off
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:	est>echo %cmdcmdline%
%cmdcmdline%

动态值根本不是真正的环境变量,这就是 SET 命令或 ENV.JS 无法访问它们的原因.CMD.EXE 中的变量扩展代码首先检查变量的进程环境变量,只有在没有找到时才会将名称与特殊动态名称列表进行比较.每个动态变量"都必须存在特殊的 CMD.EXE 代码,才能从适当的源获取值.

The dynamic values are not really environment variables at all, which is why they are not accessible to the SET command or to ENV.JS. The variable expansion code in CMD.EXE first checks the process environment variables for the variable, and only if not found does it compare the name against the list of special dynamic names. Special CMD.EXE code must exist for each dynamic "variable" to derive the value from the appropriate source.

微软的 Raymond Chen 在他的博客中描述了这类动态变量的行为 - 旧的新事物

The behavior of this class of dynamic variables is described by Microsoft's Raymond Chen within his blog - The Old New Thing

2) 以 =

=ExitCode
=ExitCodeAscii
=C:
=D:
...
=Z:

在执行定义它的某个命令之前,这些动态值中的每一个都是未定义的.例如,一个全新的 CMD.EXE 控制台会话以 =ExitCode undefined 开头.一旦执行设置返回码的外部命令,它就会被定义.

Each of these dynamic values is undefined until some command is executed that defines it. For example, a brand new CMD.EXE console session starts with =ExitCode undefined. It becomes defined once an external command is executed that set a return code.

有一个例外,即始终定义当前目录对应的 ={driveLetter}: 变量,即使在 CMD.EXE 第一次启动时也是如此.

There is one exception in that the ={driveLetter}: variable corresponding to the current directory will always be defined, even when CMD.EXE first starts up.

不可能使用 SET 来定义任何这些变量,因为 SET 不允许在变量名中使用 =.但是底层进程环境变量空间确实允许 = 在变量名中.它必须在 CMD.EXE 上下文之外完成.

It is impossible to use SET to define any of these variables because SET does not allow = in a variable name. But the underlying process environment variable space does allow = in variable names. It just must be done outside of the CMD.EXE context.

我编写了一个额外的 TEST.JS 来帮助测试这些变量:

I've written an additional TEST.JS to help test these variables:

var shell=WScript.CreateObject("WScript.Shell");
var env=shell.Environment("Process");
WScript.echo('Within JScript: ExitCode='+env("=ExitCode"));
env("=ExitCode") = "override";
WScript.echo('Within JScript after override: ExitCode='+env("=ExitCode"));
WScript.echo('Within JScript test.bat return code = '+shell.run("cmd /c test.bat",10,1));
WScript.echo('Within JScript after test.bat: ExitCode='+env("=ExitCode"));

反过来,TEST.JS 调用 TEST.BAT:

In turn, TEST.JS calls TEST.BAT:

@echo off
echo Within test.bat: ExitCode=%=ExitCode%
cmd /c exit 10
echo =Within test.bat: ExitCode=%=ExitCode%
pause
exit %errorlevel%

以下是使用 =ExitCode 的一些测试结果,从全新的 CMD.EXE 会话开始:

Here are some test results using =ExitCode, starting with a brand new CMD.EXE session:

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:	est>echo %=ExitCode%
%=ExitCode%

C:	est>set "=ExitCode=override"
The syntax of the command is incorrect.

C:	est>cscript //nologo env.js =ExitCode
=ExitCode=

C:	est>REM cscript is an external command that set the value!

C:	est>echo %=ExitCode%
00000000

C:	est>set =
The syntax of the command is incorrect.

C:	est>set ""|findstr /b =ExitCode
=ExitCode=00000000

C:	est>cscript //nologo env.js =ExitCode
=ExitCode=00000000

C:	est>cscript //nologo test.js
Within JScript: ExitCode=00000000
Within JScript after override: ExitCode=override
Within JScript test.bat return code = 10
Within JScript after test.bat: ExitCode=override

C:	est>

以下是 TEST.JS 在新窗口中启动的 TEST.BAT 的结果:

Here are the results of TEST.BAT that TEST.JS launched in a new Window:

Within test.bat: ExitCode=override
Within test.bat: ExitCode=0000000A
Press any key to continue . . .

我相信这些动态变量是真正的环境变量,这就是为什么 SET 和 JScript 都可以访问它们的原因.(SET 只能使用特殊的 SET "" 语法访问该值.)每次执行相关命令时,CMD.EXE 都会动态定义(或更新)变量.ENV.JS 和 TEST.JS 可以看到调用 CMD.EXE 会话设置的值.TEST.BAT cmd 会话可以看到 TEST.JS 设置的继承覆盖值.但是 JScript 在 TEST.BAT 退出后继续获取覆盖值,因为 CMD.EXE 没有用返回码更新值.

I believe that these dynamic variables are true environment variables, which is why both SET and JScript can access them. (SET can only access the value using the special SET "" syntax.) The variables are dynamically defined (or updated) by CMD.EXE each time a relavent command is executed. ENV.JS and TEST.JS can see the value that was set by the calling CMD.EXE session. The TEST.BAT cmd session could see the inherited override value that TEST.JS set. But JScript continued to get the override value after TEST.BAT exited because CMD.EXE was not there to update the value with the return code.

无论是启用还是禁用命令扩展,此类动态变量都可用.即使扩展程序被禁用,动态值也会保持不变,如下所示:

This class of dynamic variables is available regardless whether command extensions are enabled or disabled. The dynamic values are maintained even when extensions are disabled, as evidenced below:

C:	est>cmd /e:off
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:	est>echo %=c:%
C:	est

C:	est>cd test

C:	est	est>echo %=c:%
C:	est	est

3) __CD__ - 一个特殊的情况!
编辑 - 实际上,__APPDIR__ 的工作方式相同

此动态变量始终可用于 CMD.EXE 和 JScript.可以定义覆盖值,但是 CMD.EXE 和 JScript 都不能看到覆盖值,除了 SET 命令可以列出覆盖值.(同样,未显示,但 jeb 发现 SET/A 可以读取覆盖值,如果它是数字).

This dynamic variable is always available to both CMD.EXE and JScript. An override value can be defined, but neither CMD.EXE nor JScript can see the override value, except the SET command can list the override value. (Also, not shown, but jeb discovered SET /A can read the override value if it is numeric).

我又写了一个 TEST2.JS 来探测这个变量.

I wrote yet another TEST2.JS to probe this variable.

var shell=WScript.CreateObject("WScript.Shell");
var env=shell.Environment("Process");
WScript.echo('Within JScript: __CD__='+env("__CD__"));
env("__CD__") = "JS override";
WScript.echo('Within JScript after override: __CD__='+env("__CD__"));
shell.run('cmd /c "set __CD__&pause",1,0');

以下是一些测试的结果:

Here are the results of some tests:

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:	est>echo %__CD__%
C:	est

C:	est>set __CD__
Environment variable __CD__ not defined

C:	est>set "__CD__=Batch override"

C:	est>echo %__CD__%
C:	est

C:	est>set __CD__
__CD__=Batch override

C:	est>cscript //nologo test2.js
Within JScript: __CD__=C:	est
Within JScript after override: __CD__=C:	est

C:	est>

下面是TEST2.JS打开的CMD.EXE窗口的结果:

Here is the result of the CMD.EXE window that TEST2.JS opened up:

__CD__=JS override
Press any key to continue . . .

如果我如下定义 ENV.JS 的快捷方式:

If I define a shortcut to ENV.JS as follows:

Target:   C:	estenv.js __CD__
Start in: C:	estxyz

然后当我点击它时,我会收到一个警告框,说明:

Then when I click on it, I get an alert box stating:

__CD__=C:	estxyz

我发现这些结果令人着迷.动态值不能是真正的环境变量.大概有一个低级 OS 环境变量访问例程,当它被要求返回 __CD__ 的值时,它会自动返回进程的当前目录.即使定义了名为 __CD__ 的真正静态环境变量,它也会这样做.

I find these results fascinating. The dynamic value must not be a true environment variable. Presumably there is a low level OS environment variable access routine that automatically returns the process's current directory whenever it is asked to return the value of __CD__. It does so, even if a true static environment variable named __CD__ is defined.

CMD.EXE SET 命令必须以不同于大多数其他上下文的方式访问环境变量.我想可以编写一个 C 程序来获取指向进程环境内存的指针并解析任何真正的用户定义的 __CD__ 值,就像 SET 命令一样.

The CMD.EXE SET command must access the environment variable differently than most other contexts. I imagine a C program could be written to get a pointer to the process environment memory and parse any true user defined __CD__ value, much as the SET command.

鉴于它是一个低操作系统例程提供此值,即使命令扩展被禁用,%__CD__% 仍然可用也就不足为奇了.

Given that it is a low operating system routine that provides this value, it is not surprising that %__CD__% is available even when command extensions are disabled.

C:	est>cmd /e:off
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:	est>echo %__cd__%
C:	est

C:	est>cd test

C:	est	est>echo %__cd__%
C:	est	est

我认为从操作系统的角度来看,当前目录的概念对于每个进程都至关重要,并且 MS 决定通过动态虚拟环境变量让进程访问该值.XP OS 允许扩展任何用户定义的 __CD__ 覆盖值.也许这对某些应用程序造成了问题,并且 MS 决定修改环境访问例程(也许是从 Vista 开始?)以始终返回真正的当前目录,而不管用户定义的任何 __CD__ 变量如何.

I suppose the concept of a current directory is critical for every process from an OS perspective, and MS decided to give a process access to the value via a dynamic virtual environment variable. The XP OS allows expansion of any user defined __CD__ override value. Perhaps that caused problems for some applications, and MS decided to modify the environment access routines (starting with Vista perhaps?) to always return the true current directory, regardless of any user defined __CD__ variable.

因此,基于返回当前目录是低级例程的理论,我现在认为不可能使用本机批处理命令可靠地获取 __CD__ 的任何用户定义值.

So, based on the theory that it is a low level routine that is returning the current directory, I now believe it is impossible to use native batch commands to reliably get any user defined value for __CD__.

这篇关于为什么我不能在 Windows 7 上访问名为 __CD__ 的变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆