1

Im trying to make a program that selects a file name, then pipes it into a variable.

My Attempt:

Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)

After its used it gives out

myVar:1.14.4

the plan was for it to go into and echo command so i made it like this

@echo off
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
echo e %myVar%
cmd /k

but all that happens is

e

What am I doing wrong? Also, is there a way to do this with FOR?

2
  • 1
    The proper way to process/parse the output of another command in batch is for /f. The myVar in your 1st example is only valid in the scope of the (code block) and is not stored in the environment. For details see How does the Windows Command Interpreter (CMD.EXE) parse scripts?
    – LotPings
    Commented Jul 25, 2019 at 7:11
  • The change of variable myVar gets lost, because pipes create new cmd instances for either side, so myVar is assigned in the cmd instance right to the pipe only...
    – aschipfl
    Commented Jul 25, 2019 at 9:03

1 Answer 1

2

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 /F option.

For example, the following will simply list all the files:

for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do echo %%~nxF

The ~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"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .