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

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

问题描述

注意 - 这个问题是基于Windows 7的基于MC ND的答案,Foxidrive的评论观察到的行为,它并不适用于XP

我可以使用伪动态变量%CD%来得到当前目录,没有结尾的 \\ 。如果我定义使用设置CD = someValue中命名CD真正的变量,那么%CD%返回值我分配的,而不是当前目录。

有一个鲜为人知的动态变量%__ CD __%,这是一样的%CD%,除了它包括尾随 \\ 。但是,如果我做的设置__CD __ = someValue中,我无法访问我分配的值!我可以使用设置__CD __ 来看到我的变量,我分配的值存在,但%__ CD __%总是返回当前目录!

没有人有任何想法如何 __%__ CD%机制的工作(为什么它比任何其他动态变量不同)?

有人能想出一个方法来访问我的 __ CD __ 仅仅使用标准的批处理命令变量(不解析的输出设置__CD __ )?

这更是一个学术问题,而不是一个实际的问题。谁也不能确定相匹配的动态变量名称变量。


我不想要一个例程解析的结果集__CD __ 的原因是因为值可以在他们换行符。有人可能会定义两个变量, __ CD __ __ CD__2 ,也可以定义一个 __ CD __ 用含换行,然后按 __ CD__2 = ... 值。这将是不可能的那些两种情况之间进行区分。 (正如我所说,这是一个学术问题,而不是一个实际的问题!)


解决方案

我有一个理论如何以及为什么 __ CD __ 行为差异如此之比任何其它伪环境变量。

我写了一个简单的脚本ENV.JS探测过程中的环境。

  VAR ENV = WScript.CreateObject(WScript.Shell),环境(过程)。
WScript.echo(ENV(WScript.Arguments.Item(0)));

ENV.JS期望一个环境变量名作为唯一参数,并简单地打印变量的值。我做了一个Windows 7计算机上我的测试。脚本可以从CMD.EXE控制台内运行,或者它可以直接通过定义该参数的快捷方式运行。

我会在各个动态变量进行分类,呈现对比的行为,以理论为通过他们的工作机制一起。

有一些动态变量,可以分为三大类:

1)正常找变量,没有任何preFIX或后缀

  CD当前目录
日期当前日期
TIME当前时间
ERRORLEVEL当前ERRORLEVEL
0和32767之间的随机随机整数
CMDEXTVERSION当前的扩展级(仅当扩展被启用可用)
CMDCMDLINE调用该电流水平CMD.EXE命令行

动态值只能通过扩展现有内CMD.EXE,只有当启用了命令扩展。它们不是通过设定用,或者通过ENV.JS.动态值可以通过显式定义使用设置一个静态值覆盖。的倍率值可通过SET和ENV.JS可用。

  C:\\试验>回声%CMDCMDLINE%
C:\\ WINDOWS \\ SYSTEM32 \\ CMD.EXEC:\\试验>集CMDCMDLINE
环境变量CMDCMDLINE没有定义C:\\试验> // CSCRIPT NOLOGO env.js CMDCMDLINE
CMDCMDLINE =C:\\试验>集CMDCMDLINE =覆盖C:\\试验>回声%CMDCMDLINE%
覆盖C:\\试验>集CMDCMDLINE
CMDCMDLINE =覆盖C:\\试验> // CSCRIPT NOLOGO env.js CMDCMDLINE
CMDCMDLINE =覆盖C:\\试验> CMD / E:关闭
微软的Windows [版本6.1.7601]
版权所有(c)2009年微软公司。版权所有。C:\\试验>回声%CMDCMDLINE%
%CMDCMDLINE%

动态值都没有真正的环境变量,这就是为什么他们不SET命令或ENV.JS.访问在CMD.EXE的变量扩展code首先检查过程中的环境变量的变量,只有当没有发现它比较名称针对特殊的动态名称列表。特别CMD.EXE code必须存在每个动态变量,从适当的源获得的价值。

这个类的动态变量的行为是由微软的雷蒙德陈他的博客中描述的 - 的旧的新

2) = pfixed动态变量$ P $

  =退出code
=退出codeAscii
= C:
= D:
...
= Z:

直到执行一些命令定义它每一个动态值是不确定的。例如,一个全新的CMD.EXE控制台会话与=退出code不确定的开始。一旦执行一个外部命令设置返回code就变成定义。

有是一个例外 = {}为驱动器:对应于当前目录变量总是被定义,即使CMD.EXE第一次启动

这是不可能使用SET来定义这些变量,因为SET不允许 = 在变量名。但潜在的进程环境变量空间确实让 = 中的变量名。它只是必须在CMD.EXE背景之外完成。

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

  VAR壳= WScript.CreateObject(WScript.Shell);
VAR ENV = shell.Environment(过程);
WScript.echo('在JScript中:退出code ='+ ENV(=退出code));
ENV(=退出code)=覆盖;
WScript.echo('重写后的JScript中:退出code ='+ ENV(=退出code));
WScript.echo('在JScript中TEST.BAT返回code ='+ shell.run(CMD / C test.bat的,10,1));
WScript.echo(test.bat的后的JScript中:退出code ='+ ENV(=退出code));

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

 关闭@echo
内回声test.bat的:退出code =%=退出code%
CMD / C出口10
回声=在test.bat的:退出code =%=退出code%
暂停
退出%ERRORLEVEL%

下面是使用 =退出code ,一些测试结果,从一个全新的CMD.EXE会话:

 的Microsoft Windows [版本6.1.7601]
版权所有(c)2009年微软公司。版权所有。C:\\试验>回声%=退出code%
%=退出code%C:\\试验>设置=退出code =覆盖
该命令的语法不正确。C:\\试验> // CSCRIPT NOLOGO env.js =退出code
=退出code =C:\\试验> REM CSCRIPT是一个外部命令设置的值!C:\\试验>回声%=退出code%
00000000C:\\试验> =集
该命令的语法不正确。C:\\试验>集,| FINDSTR / B =退出code
=退出code = 00000000C:\\试验> // CSCRIPT NOLOGO env.js =退出code
=退出code = 00000000C:\\试验> // CSCRIPT NOLOGO test.js
在JScript中:退出code = 00000000
在JScript中后置:退出code =覆盖
在JScript中回报率下的te​​st.bat code = 10
在之后的JScript的test.bat:退出code =覆盖C:\\试验>

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

 在test.bat的:退出code =覆盖
在test.bat的:退出code = 0000000A
preSS任意键继续。 。 。

我相信,这些动态变量为真环境变量,这就是为什么既SET和JScript可以访问它们。通过CMD.EXE每次执行relavent命令时(SET只能访问使用特殊设置语法的值。)的变量动态定义(或更新)。 ENV.JS和TEST.JS可以看到被调用CMD.EXE会话设置的值。该TEST.BAT CMD会话可以看到TEST.JS设置继承倍率值。但JScript中继续得到倍率值TEST.BAT退出后,因为CMD.EXE是不存在更新与返回code的值。

本类动态变量是可用的命令扩展不管是否启用或禁用。动态值保持甚至当扩展被禁用,如下证明:

  C:\\试验> CMD / E:关闭
微软的Windows [版本6.1.7601]
版权所有(c)2009年微软公司。版权所有。C:\\试验>回声%= C:%
C:\\测试C:\\试验> CD测试C:\\试验\\试验>回声%= C:%
C:\\测试\\测试

3)__CD__ - 一种特殊的情况下,所有你们自己

这动态变量始终可用既CMD.EXE和JScript。覆盖值可以被定义,但无论CMD.EXE也不JScript中可以看到倍率值,除了SET命令可以列出倍率值。 (另外,没有显示,但是杰布发现SET / A可以读取倍率值,如果它是数字)。

我写了另一个TEST2.JS探讨这个变量。

  VAR壳= WScript.CreateObject(WScript.Shell);
VAR ENV = shell.Environment(过程);
WScript.echo('在JScript中:__CD __ ='+ ENV(__ CD__));
ENV(__ CD__)=JS覆盖;
WScript.echo('重写后的JScript中:__CD __ ='+ ENV(__ CD__));
shell.run(CMD / C组__CD __&安培;暂停,1,0');

下面是一些试验的结果:

 的Microsoft Windows [版本6.1.7601]
版权所有(c)2009年微软公司。版权所有。C:\\试验>回声%__ __ CD%
C:\\测试\\C:\\试验>设置__CD__
环境变量__CD__没有定义C:\\试验>设置__CD __ =批覆盖C:\\试验>回声%__ __ CD%
C:\\测试\\C:\\试验>设置__CD__
__CD __ =批次覆盖C:\\试验> // CSCRIPT NOLOGO test2.js
在JScript中:__CD __ = C:\\测试\\
在JScript中覆盖后:__CD __ = C:\\测试\\C:\\试验>

下面是TEST2.JS打开了cmd.exe窗口的结果是:

  __ __ CD = JS覆盖
preSS任意键继续。 。 。

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

 目标:C:\\测试\\ env.js __CD__
启动:C:\\测试\\ XYZ

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

  __ __ CD = C:\\测试\\某某\\

我觉得这些结果令人着迷。动态值不能是一个真正的环境变量。 presumably有一个低的水平OS环境变量访问程序时,它被要求返回的值__ __ CD 自动返回进程的当前目录。它这样做,即使真正的静态环境变量命名为 __ __ CD 定义。

该CMD.EXE SET命令必须以不同访问环境变量比大多数其他上下文。我想一个C程序可以写获取一个指针进程环境记忆和分析定义的任何真正的用户 __ CD __ 价值,就像SET命令。

由于它是低的操作系统程序提供此值,这并不奇怪,%__ CD __%可即使命令扩展将被禁用。

  C:\\试验> CMD / E:关闭
微软的Windows [版本6.1.7601]
版权所有(c)2009年微软公司。版权所有。C:\\试验>回声%__ __ CD%
C:\\测试\\C:\\试验> CD测试C:\\试验\\试验>回声%__ __ CD%
C:\\测试\\测试\\

我想一个当前目录的概念是从操作系统的角度看每一道工序的关键,MS决定给通过动态虚拟环境变量的过程获得的价值。在XP操作系统允许定义 __ __ CD 倍率值的任何用户的扩展。也许这导致问题对于某些应用,而MS决定修改环境访问例程(与Vista开始吧?)始终返回真正的当前目录,无论定义的任何用户的 __ CD __ 变量。

所以,理论的基础上,这是返回当前目录下的低水平常规,我现在认为这是不可能使用本地批处理命令可靠地获得 __ CD的任何用户定义的值__

Note - this question is based on behavior observed on Windows 7. Based on MC ND's answer, and Foxidrive's comments, it does not apply to XP.

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.

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!

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

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.


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 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!)

解决方案

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

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 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) Normal looking "variables" without any prefix or suffix

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

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:\test>echo %cmdcmdline%
"C:\Windows\system32\cmd.exe"

C:\test>set cmdcmdline
Environment variable cmdcmdline not defined

C:\test>cscript //nologo env.js cmdcmdline
cmdcmdline=

C:\test>set cmdcmdline=override

C:\test>echo %cmdcmdline%
override

C:\test>set cmdcmdline
cmdcmdline=override

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

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

C:\test>echo %cmdcmdline%
%cmdcmdline%

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.

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

2) Dynamic variables prefixed with =

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

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.

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.

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.

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"));

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%

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:\test>echo %=ExitCode%
%=ExitCode%

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

C:\test>cscript //nologo env.js =ExitCode
=ExitCode=

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

C:\test>echo %=ExitCode%
00000000

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

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

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

C:\test>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:\test>

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 . . .

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:\test>cmd /e:off
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\test>echo %=c:%
C:\test

C:\test>cd test

C:\test\test>echo %=c:%
C:\test\test

3) __CD__ - A special case all unto itself!

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).

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:\test>echo %__CD__%
C:\test\

C:\test>set __CD__
Environment variable __CD__ not defined

C:\test>set "__CD__=Batch override"

C:\test>echo %__CD__%
C:\test\

C:\test>set __CD__
__CD__=Batch override

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

C:\test>

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

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

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

Target:   C:\test\env.js __CD__
Start in: C:\test\xyz

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

__CD__=C:\test\xyz\

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.

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.

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:\test>cmd /e:off
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\test>echo %__cd__%
C:\test\

C:\test>cd test

C:\test\test>echo %__cd__%
C:\test\test\

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.

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__.

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

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