Are environment variables expanded when searching PATH? - windows

This question expands on the comments on this deleted answer. I claimed that an unexpanded variable reference in the PATH would not be expanded when searching for an executable, but Ken said he didn't see the same behaviour that I did.
Note that the ordinary situation is subtly but critically different: subject to certain conditions, environment variables are automatically expanded when the PATH environment variable is built from the information in the registry. I'm talking about the case where, for one reason or another, this hasn't happened, so the actual environment block of the cmd.exe process contains a PATH which still has environment variable references in it.
Here is the code I built to test this behaviour:
md test1
echo echo hello! > test1\test1.cmd
set TESTPATH=%cd%\test1
set percent=%%
set PATH=c:\windows\system32;c:\windows;c:\windows\system32\Wbem;%percent%TESTPATH%percent%
set PATH
set TESTPATH
test1
cmd /c test1
start test1.cmd
and this is the result on my machine:
C:\working\testpath>test
C:\working\testpath>md test1
C:\working\testpath>echo echo hello! 1>test1\test1.cmd
C:\working\testpath>set TESTPATH=C:\working\testpath\test1
C:\working\testpath>set percent=%
C:\working\testpath>set PATH=c:\windows\system32;c:\windows;c:\windows\system32\
Wbem;%TESTPATH%
C:\working\testpath>set PATH
Path=c:\windows\system32;c:\windows;c:\windows\system32\Wbem;%TESTPATH%
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.py;.pyw
C:\working\testpath>set TESTPATH
TESTPATH=C:\working\testpath\test1
C:\working\testpath>test1
'test1' is not recognized as an internal or external command,
operable program or batch file.
C:\working\testpath>cmd /c test1
'test1' is not recognized as an internal or external command,
operable program or batch file.
C:\working\testpath>start test1.cmd
The system cannot find the file test1.cmd.
What is the expected behaviour? Does it vary depending on the version of Windows and/or other factors?

There are two entirely different points of view in this question:
Q: How to expand the values of variables embedded in another one? This point is not specific to PATH variable, but works on anyone.
A: Enclose the names of the variables in exclamation marks and enable delayed expansion when you want to expand such values:
#echo off
setlocal EnableDelayedExpansion
set TESTPATH=%cd%\test1
set "PATH=c:\windows\system32;c:\windows;c:\windows\system32\Wbem;^!TESTPATH^!"
set PATH
echo PATH=%PATH%
Q: Does cmd.exe such delayed expansion when it use PATH to locate an executable file?
A: No. cmd.exe uses the values in PATH variable as they appear, with no further processing. Any special character that may appear in PATH, like percents or exclamation-marks, are taking literally.

Related

How do I get and print value of an environment variable?

I want to print value from a Windows environment variable, say, path or errorlevel, I've tried this but it doesn't work. Output this in my console:
(without consider spaces/tabs which it outputs):
echo %PATH
%PATH
Makefile:
PATH=$(PATH);\nonesuch
all:
echo %PATH%
command-line:
nmake /E
How do I fix it?
NOTE: Visual Studio's binary path is in my PATH variable, that's why I'm calling this outside VS console
The percent sign % has special meaning in Makefiles.
In order to perform the Windows batch-file substitution, you need to escape it like this:
echo %%PATH%%
This seems to work too:
"echo %PATH%"
Another option is to perform the substitution on the Make side, but that's a different thing:
echo $(PATH)
To view your path, just try out this
echo $PATH

echo %cd% alias does not respond as it should

I have created and alias named pwd for echo %cd% (#DOSKEY pwd=echo %cd%). I have saved it in bat file and configured it to autorun with command processor.
Now whenever I run the command pwd in my command processor it returns with the C:\windows\system32 no matter in which path I am currently in. whereas when I run the echo %cd% it returns the right path I am in.
How do I solve this problem? Is it because of the parameter I am passing to echo? This parameter should update according to the path I am going in. It seems it updates just once when the command prompt is loaded with aliases.
That is because %cd% is expanded during the definition of the macro, not when it is executed.
From a batch file, you should use:
#DOSKEY pwd=echo %%cd%%
If defining from the command line, the expansion rules are different, so you would need something like:
DOSKEY pwd=echo %^cd%
But there is an even simpler method that works in all cases. The CD command without arguments simply lists the current directory. Just enclose the command in parentheses to prevent arguments from being passed.
#DOSKEY pwd=(cd)

How is it possible to view windows environment variable without executing arguments within it?

Basically I would like to export my exact PATH variable to a file automatically. It contains things like %ANT_HOME%/bin and I would like to keep it that way. From what I could find, using both set and echo will execute that argument and give me the absolute path. Is there something I'm missing?
To get a copy of your PATH without expansion of environment variables you could save the following as "rawPath.vbs"...
Option Explicit
Dim wsh
Set wsh = CreateObject("Wscript.Shell")
Wscript.Echo wsh.RegRead("HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\Path")
...and then issue the following command to pipe the output to a file
cscript -nologo rawPath.vbs > myPath.txt
Do you see %ANT_HOME% when you execute SET from the prompt?
If so,
>filename echo %path%
should export the path as desired.
If the PATH variable does not actually contain the "%" characters, then it's already been resolved. And remember, "%" is actually a legitimate (but annoying) filename character...
You CAN set a "%" character into an environment variable
set var=%%something%%
will set var to %something%
You need to escape the % good sir, example
>echo %path%
C:\windows\system32;C:\windows\system32\wbem
>echo ^%path^%
%path%

Who defines %cd% for my batch?

The following batch script prints out my current working directory.
echo %cd%
But I didn't define the cd variable. So who does this? Is there anything else like this?
I also checked the Environment Variables, there's none with the name of cd. So is this built into the cmd.exe?
Thanks.
see HELP SET ...
If Command Extensions are enabled,
then there are several dynamic
environment variables that can be
expanded but which don't show up in
the list of variables displayed by
SET. These variable values are
computed dynamically each time the
value of the variable is expanded. If
the user explicitly defines a variable
with one of these names, then that
definition will override the dynamic
one described below:
%CD% - expands to the current
directory string.
%DATE% - expands to current date using
same format as DATE command.
%TIME% - expands to current time using
same format as TIME command.
%RANDOM% - expands to a random decimal
number between 0 and 32767.
%ERRORLEVEL% - expands to the current
ERRORLEVEL value
%CMDEXTVERSION% - expands to the
current Command Processor Extensions
version number.
%CMDCMDLINE% - expands to the original
command line that invoked the
Command Processor.
Run SET /? and in the end you'll find the answer and some other vars like that as well.
The value is stored by the command shell, I believe.
It's a built-in behavior of the batch processor, and has the same basic behavior as ERRORLEVEL.

Batch file equivalent of Unix parameter expansion with quotes

There have been a lot of questions asked and answered about batch file parameters with regards to the %*, but I haven't found an answer for this.
Is there an equivalent syntax in batch files that can perform the same behavior as "$#" in Unix?
Some context:
#echo off
set MYPATH=%~dp0
set PYTHON=%MYPATH%..\python\python
set BASENAME=%~n0
set XTPY=%MYPATH%..\SGTools\bin\%BASENAME%.py
"%PYTHON%" "%XTPY%" %*
This is the .bat file that is being used a proxy to call a Python script. So I am passing all the parameters (except the script name) to the Python script. This works fine until there is a parameter in quotes and/or contains spaces.
In shell scripts you can use "$#" to take each parameter and enclose it in quotes. Is there something I can do to replicate this process?
Example calls:
xt -T sg -t "path with possible spaces" -sum "name with spaces" -p <tool_name> -o lin32 lin64 win32 <lots of other options with possibilities of spaces>
The command/file xt simply contains the code listed above, because the actual executable is Python code in a different folder. So the point is to create a self-contained package where you only add one directory (xbin directory) to your path.
I'm not sure what the cleanest solution is, but here is how I worked around the problem:
setlocal EnableDelayedExpansion
for %%i in (%*) do set _args= !_args! "%%~i"
echo %_args%
%_args% will now contain a quoted list of each individual parameter. For example, if you called the batch file as follows:
MYBATFILE "test'1'file" "test'2'file" "test 3 file"`
echo %_args%
will produce the original quoted input.
I needed this for CMD files that take unfriendly file or directory names and pass them to Cygwin Bash shell scripts which do the heavy lifting, but I couldn't afford to have the embedded single quotes or spaces lost in the transition.
Note the ~i in %%~i% which is necessary to remove quotes before we apply quotes. When a parameter containing spaces is passed (e.g., "test 3 file" above), the CMD shell will already have applied quotes to it. The tilde here makes sure that we don't double-quote parameters containing spaces.

Resources