Use an expanded variable in for loop - windows

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.

Related

How to use global variables in For loop - Windows CMD

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.

How do I return a variable from a called batch file to the caller?

I want to be able to call a batch file like it were a function in Java or something of the like. Would it be possible to do something such as
set answer=call Calculate.bat %input1% %input2%
Where calculate.bat would calculate the sum of the two inputs, then it would assign it to the answer variable in the original batch file. Is this possible in some way?
If you use setlocal in your script like #SomethingDark said, you could to decide to transmit only certain variable
#ECHO OFF
setlocal
REM your code here, for example:
set /A "output=%1 + %2" > NUL
endlocal & set "answer=%output%"
REM variable %output% does not exist anymore
REM only %answer% remain changed (and stay the same once the script end)
like #Harry johnston said, if you set a variable in the batch file you called the variable will set in the caller to. if you do not want set any variables in the batch file you call, do:
for /f %%a in ('calculate.bat %input1% %input2%') do set "output=%%a"
the output of your command is stored in %output%

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.

Windows Batch - Findstr and assign to a variable

I am trying to find a string in a file and assign the results to a variable for further processing. But for some reasons the code below doesn't work.
My string is always available on the 2nd line so I tried the code below, from which I can print the correct string on the console, but cannot assign it to a variable:
for /f "tokens=1*delims=:" %%G in ('findstr /n "^" C:\myfolder\payload.xml') do if %%G equ 2 echo %%H
Problem: Using the above method I'm unable to store the result in a variable
I have tried another method as well:
findstr /g "FilePath" C:\myfolder\payload.xml>>D:\Data\tmp.txt
set /p "Prev_FileName="<D:\Data\tmp.txt
echo %Prev_FileName%
Problem: with this method getting the output in the file tmp.txt but not in the variable.
In both contexts used SETLOCAL EnableDelayedExpansion
Could you please help as I am a beginner?
There are no unusual steps that need to be taken to set a variable in either context. How do you know the variable has not been set?
The first code you posted does not attempt to set anything, though if you changed the echo %%H into set "Prev_FileName=%%H", then it should work just find.
The second code should be setting the variable.
Why do you think your variable is not being set? I suspect you are doing something like echo %Prev_FileName%, and not seeing your expected result. That could happen if you are within a parenthesized block of commands, since they are all parsed at once, and %Prev_FileName% is expanded at parse time. You say you setlocal enableDelayedExpansion, but that does nothing unless you you also change the syntax for variable expansion. You should use echo !Prev_FileName! instead.

Determine Number of Tokens - BATCH

I'm currently working on a mass user creation script through PowerShell and Batch. At the moment the script is 95 lines and is the largest script I've ever written in Batch.
I want the script to be as automated as possible and plan to give it to clients that need help creating a mass number of users. To do this, I have a 21 line settings file and one of the variables that I need is the full domain name (This is needed for dsadd)
The problem with this is that users may have any number of variables for this - anywhere from two in testlabs to four in places like schools. I am so far able to separate the tokens however I need them all stored as variables like %%a, %%b and not to store everything as %%a. The number of tokens will be dynamic so I need some sort of solution to this. Something like this (Yes I know this is not the correct syntax):
if number of tokens=4 (
dsadd "cn=%%a,ou=%%b,dc=%DSuffix1%,dc=%DSuffix2%,dc=%DSuffix3%,dc=%Dsuffix4% )
In that line %%a and %%b are variables in another for loop later in the code that reads from a user list excel file. I would need something like that for anything from two tokens to four tokens. I don't mind if the solution to this is not purely BATCH however that is my preferred option.
Thanks.
EDIT: Here is the for loop I have at the moment, this is nested in another larger for loop that adds the users:
for /f "tokens=1,2,3,4 delims=." %%a in (Settings.ini) do (
set L=22
if !L!=22 set DSuffix1=%%a&& set DSuffix2=%%b&& set DSuffix3=%%c&& set DSuffix4=%%d
)
The settings.ini file contains various settings such as the Exchange server and path to the user's home directory. The line I need to interpret is line 22 which looks like this:
DOMAINNAME.SUFFIX(.SUFFIX.SUFFIX.SUFFIX)
A real life example would be:
testlab.local
or
testlab.ghamilton.local
For a testlab the setting should only be the domainname and suffix although for others such as schools or institutions the number of domain suffixes can go up to four. I want to interpret this.
EDIT: Managed to indent code correctly, sorry.
If I understand you right, you have a string such as domain.foo.bar.baz and you want to change that to dc=domain,dc=foo,dc=bar,dc=baz.
How about this?
set domain=domain.foo.bar.baz
echo dc=%domain:.=,dc=%
That should echo this:
dc=domain,dc=foo,dc=bar,dc=baz
That %domain:.=,dc=% line is expanding the %domain% environment variable, but replacing all . with ,dc=. See http://ss64.com/nt/syntax-replace.html for more details.
To do string replacement in an environment variable, you do need the value to be in an environment variable first. Here's a script that will read line 22 from settings.ini, combined with the above technique:
setlocal enabledelayedexpansion
set L=0
for /f %%a in (settings.ini) do (
set /a L=!L! + 1
if !L! equ 22 (
set domain=%%a
echo dc=!domain:.=,dc=!
)
)
L is being used to count what line we're on. When we reach line 22, we set an environment variable to the value of the entire line (%%a), then do the string substitution as above (but with ! rather than % to take advantage of delayed expansion).
Of course instead of an echo, you would do something like
dsadd "cn=%cn%,ou=%ou%,dc=!domain:.=,dc=!"
Here's my little snippet to sort of demonstrate how to get the separate tokens (the delims are space and tab, but you can change them).
#echo off & setlocal enabledelayedexpansion
for /f "tokens=1,2,3,4" %%a in (test.txt) do (
set token1=%%a
set token2=%%b
set token3=%%c
set token4=%%d
set full=%%a%%b%%c%%d
)
set token
set full
pause>nul
test.txt contains:
first second third
The output was:
token1=first
token2=second
token3=fourth
full=firstsecondthird
So, you could judge how many tokens there is by something like
for /l %%i in (4,-1,1) do if not defined token%%i set amount=%%i
Or something along the same lines.
Hope that helps.

Resources