What am I doing wrong?
Simple - you are trying to use a technique that cannot work ;-) It is impossible to use piped command output to set environment variables in your parent environment because of the way Windows pipes work.
Your script is running in a command process - lets call it the parent.
A Windows pipe launches two child command processes, each with its own separate environment space. The left side of the pipe is executed in the first child, and the right in the second. The pipe sends the output of the first child as input to the second child. The
SET /P successfully defines the new myVar variable in the child process and the
SET MYVAR command displays the value. Great.
But then the pipe ends, and both child processes are terminated, and their associated environments disappear. There is no way to transfer the myVar environment value from the child pipe process back to your parent environment.
There are many surprising side effects of the Windows pipe design that confuse anyone that does not fully understand the mechanism. See https://stackoverflow.com/q/8192318/1012053 for more info. I recommend reading the question and all of the answers.
Is there a way to do this with FOR?
Yes, the proper way to capture the output of a command in an environment variable is via FOR, specifically
FOR /F as DavidPostill shows. Although there is one definite problem, one potential problem, and one inefficiency in his code.
There is no need to use
USEBACKQ when processing the output of a command. It is simpler to use regular single quote
' rather than the back tick:
for /f %%F in ('yourCommand') do ...
The error is the use of
echo myVar:%myVar% within the FOR loop body. That will display the value
myVar that existed before the loop was run because percent expansion occurs when the line is parsed, and the entire FOR loop is parsed in one step. You would need to enable delayed expansion (
setlocal enableDelayedExpansion) and then use
echo !myVar! to see the value that was set within the loop.
There is the potential for another problem - FOR /F will parse the value into space delimited tokens and only capture the first token. If your file name contains spaces, then you would not get the entire name unless you use the DELIMS option to specify no delimiter.
for /f "delims=" %%F in (....) do ....
But there is no need to use
DIR /B and
FOR /F. You can simply use a vanilla
FOR loop without the
For example, the following will simply list all the files:
for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do echo %%~nxF
~nx specifies to use only the file name and extension, discarding the drive and folder path.
Typically there is no need to use an environment variable - simply use the
%%F FOR variable within your loop to do your work.
But if you do need a value outside of the loop for some reason, you can certainly do
for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do set "myVar=%%~nxF"
But that will only capture the last file that is iterated. The myVar variable will get overwritten with each iteration. Your original design would have captured the first file that was listed (assuming it could have been made to work). Neither seems like a good idea unless you know for a fact that the Van1 folder only contains a single file.
If you need to capture all files into variable(s), then you would need to use a pseudo array. Batch does not have a formal array concept, but it can be emulated easily. You can find loads of examples if you simply search the web for "batchfile array"