How to use global variables in For loop - Windows CMD - windows

I am trying to do a very simple thing, I want to set a variable in Windows CMD and use it in a for loop, but for some reason my var is not loading inside the loop. Here's a simple example:
set myVar=someVal&&for /l %a in (0) do (echo %myVar%)
Let's say I want someVal to be echoed forever. One might assume this will print the val forever but when the loop starts it's like the variable was never set. Can someone point out what I'm missing?
I tried with single & and double &&. I also tried setlocal enabledelayedexpansion etc.

Related

Use an expanded variable in for loop

I would like to know if there is a way where I can use a for loop on an expanded variable.
Is it something recommended or which can be done?
I have a script which reads a text file which has many dimensions such as State%%20Country, City%%20Country, etc. I save them into a variable (lets call it !P!). So !P1! now has:
!P1!
City%%20Country
State%%20Country
...
The script runs a for loop and reads each row and based on that the value of !P1! changes.
I would like to know or appreciate if some one can let me know I can loop over the variable as I would like to replace the %%20 which is part of the string contained in !P1! with Space.
So what I am trying is :
for /F "delims==" %%A in ('!P1!') do ...
I know this wont work, but can someone let me know if there is a way to do this or if this is the right approach?
#ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
SET "p1=something%%%%20or%%%%20other"
SET "repl=%%%%20"
SET "p1=!p1:%repl%= !"
FOR %%a IN (%p1%) DO ECHO %%a
Not sure whether your problem has to do with a variable named !p1! or you are using delayed expansion on variable p1. The above may assist.

Batch File - Read specific line, and save a specific string in that line as a variable

Is there any way to get for /f loop (or anything else) to read a specific line?
Here is the code I have so far, it reads first word of every line.
#echo off
set file=readtest.txt
for /f "tokens=1 delims= " %%A in (%file%) do (echo %%A)
pause
If someone can point me in the right direction, it'd be much appreciated.
Thanks
Additional Information: I want to make a batch file which will rename a TXT file to a string within that TXT file, located at a specific location. I have figured out how to rename files, all I need to learn to do is to retrieve a string (located at a specific location) with in the file which will go into the name of that TXT file.
Since you haven't fully defined what you mean by "a specific location", I'll make some (reasonable, in my opinion) assumptions, though the method I present is equally valid no matter what your definition turns out to be.
You can get arbitrary lines and arbitrary words on that line by using a line counter variable in conjunction with tokens.
Let's assume your text file name can be found as the second argument on the fourth line of the infile.txt file. You can get that with something like:
#setlocal enableextensions enabledelayedexpansion
#echo off
set /a "line = 0"
for /f "tokens=2 delims= " %%a in (infile.txt) do (
set /a "line = line + 1"
if !line!==4 set thing=%%a
)
endlocal & set thing=%thing%
echo %thing%
This actually uses a few "tricks" which warrant further explanation:
the line counter to ensure you only grab what you want from a specific line, though you could change the test !line!==4 into anything you need such as a line beginning with #, the fifth line containing the string xyzzy and so on.
the use of setlocal/endlocal to effectively give you a scope from which variables cannot leak. This is good programming practice even for a language often not normally associated with such things :-)
the use of endlocal & set to bypass that scope so that thing is the only thing that does actually leak (as it should).
the use of delayed expansion and !..! variables to ensure they're correct within the for loop. Without this, the %..% will always be expand to the value they were set to when the for loop started.
Those last two bullet points are actually related. %..% variables are expanded when the command is read rather than when it is executed.
For a for loop, the command is the entire thing from the for to the final ). That means, if you use %line% within the loop, that will be evaluated before the loop starts running, which will result in it always being 0 (the variable itself may change but the expansion of it has already happened). However, !line! will be evaluated each time it is encountered within the loop so will have the correct value.
Similarly, while endlocal would normally clear out all variables created after the setlocal, the command:
endlocal & set thing=%thing%
is a single command in the context of expansion. The %thing% is expanded before endlocal is run, meaning it effectively becomes:
endlocal & set thing=whatever_thing_was_set_to_before_endlocal
That's why the use of setlocal and endlocal & set is a very useful way to limit variables "escaping" from a scope. And, yes, you can chain multiple & set stanzas to allow more variables to escape the scope.

How do I set and check a boolean variable in a for loop in a windows batch file?

I'm pretty new to windows batch files so I'm sure this question has an obvious answer but I've been digging around online for hours and haven't been able to find it. When I run the following batch file, why doesn't it output "It worked!"?
#echo OFF
SET /A _Converted="0"
SET _Converted
IF _Converted==0 (echo It worked!) ELSE (echo it didn't work)
Output:
_Converted=0
it didn't work
But sometimes (I'm not sure how to reproduce), it outputs:
Environment variable _Converted not defined
Here's what I've tried:
SET vs SET /A
Quotes in different places (SET /A "_Converted=0" vs. SET /A _Converted="0")
"If you use any of the logical or modulus operators, you will need to enclose the expression string in quotes."
My problem is in a for loop but I can reproduce the issue outside of the loop so I don't think delayed variable expansion or this question helps me even though they initially looked similar.
Put %'s around the variable before checking its value. Use delayed expansion if in a loop
As #Aacini mentioned in his comment, the following prints "It worked!":
#echo OFF
SET /A _Converted="0"
SET _Converted
IF %_Converted%==0 (echo It worked!) ELSE (echo it didn't work)
The problem was that my original issue was within a for loop and I messed with the IF statement before moving it into a simpler batch file to try to isolate the problem. So my fix will be to combine this answer with delayed variable expansion.

Windows prompt content variable as variable name

It is possible in windows command line refer to a content variable like a pointer?
Example:
SET envTEST=FOO
SET envPROD=BAR
SET CURR=envTEST
SET data=%%CURR%%
I want to data contains FOO but it contains %envTEST%
Thanks
You need multiple rounds of expansion. See How does the Windows Command Interpreter (CMD.EXE) parse scripts? for an explanation as to why the following work:
From the command line:
call set "data=%%CURR%%"
Or if delayed expansion has been enabled by cmd /v:on, then:
set "data=!%CURR%!"
From within a batch script:
call set "data=%%%CURR%%%
or
setlocal enableDelayedExpansion
...
set "data=!%CUR%!
If CURR is set and expanded within the same code block (typically done within IF or FOR loop), then:
setlocal enableDelayedExpansion
...
(
set "CURR=envTEST"
for %%V in (!CURR!) do set "data=!%%V!"
)
The CALL technique is quite slow, so I try to avoid it. It is not an issue for a single use, but it can become a major problem (slow performance) if used within a tight loop.

bat script for loop works on CL but does not work when double clicked

I have a batch file and inside the batch file, it looks in a particular directory and saves to a variable, the name of the first directory/file. Here is roughly what I am doing:
FOR /d %%F IN (%INSTALL_DIR%\dir\*) DO (
set NAME=%%~xnF
set NAME_DIR=%INSTALL_DIR%\dir\%NAME%
goto :break
)
When I run this from the command line, it works perfectly and NAME_DIR gets the correct value. However, when I double-click on the file, the NAME variable is blank. NANE_DIR is thus set to %INSTALL_DIR%\dir. Why does this happen and what can I do to fix it?
For more clarification, from the command line, this is what NAME and NAME_DIR equal when echoed:
NAME: dir1.3.8
NAME_DIR: D:\root\path\to\dir\dir1.3.8
This is what is echoed when double clicked:
NAME:
NAME_DIR: D:\root\path\to\dir
What RaymondChen told me in the comments worked! I needed to use delayed expansion. The reason for this is that windows executes the for loop as one single instruction and so it fills in all the variables at once before executing the for loop. Since I never had NAME set before the for loop, it would just evaluate to nothing. Therefore NAME_DIR gets an empty string in place of %NAME%. I noticed that when I first ran the script on the command line, it did not work. I ran it again and it worked. I kept running it and it worked every time. Thats because after running the for loop once, the variable is saved and never changed. So the next time I run the code, the variable is not blank anymore, it has the correct value. Now when double clicking, the NAME variable is null at the beginning. After the for loop executes, the value of NAME is updated. Once the script executes and the cmd windows exits, the new value of the variable is lost and it starts all over again. Here is the new code with delayed expansion:
setlocal ENABLEDELAYEDEXPANSION
FOR /d %%F IN (%INSTALL_DIR%\dir\*) DO (
set NAME=%%~xnF
set NAME_DIR=%INSTALL_DIR%\dir\!NAME!
goto :break
)
I added in the setlocal statement and changed %NAME% to !NAME!

Resources