So, I've got this basic text file called prev_batch.cfg that I want a batch script to read. prev_batch.cfg is a single line of text, but tokens are delimited with a comma. It looks something like:
apples,oranges,bananas,grapes,strawberries
I'd like each of those tokens to go into a specific variable I have setup in a for loop. The problem is only the first variable gets set within the loop. Nothing else. I want all the variables to be set to the tokens found within the delimited list in the .cfg file.
Here is what my batch script looks like up until the close of the FOR loop:
#ECHO ON
setlocal EnableDelayedExpansion
SET JOB=%1
SET USER=%2
SET ASSETROOT=%3
:: Read all the arguments for this batch script from external text file
FOR /F "delims=," %%a IN (%ASSETROOT%\users\%USER%\%JOB%\prev_batch.cfg) do (
SET JOB=%%a
SET USER=%%b
SET TEMPLATE=%%c
SET ASSETROOT=%%d
SET SHAREADDR=%%e
SET SHARENAME=%%f
SET SHAREDRIVE=%%g
SET SHAREUSER=%%h
SET SHAREPASS=%%i
)
I'm running the batch file and passing three command line parameters into it. I'm outputting the echo of the batch when it runs to a log file. And this is what I'm seeing:
C:\Windows\system32>setlocal EnableDelayedExpansion
C:\Windows\system32>SET JOB=99D0FAA9-22B8-4FE7-9321-21F5587E8177
C:\Windows\system32>SET USER=10
C:\Windows\system32>SET ASSETROOT=C:\app
C:\Windows\system32>FOR /F "delims=," %a IN (C:\app\users\10\99D0FAA9-22B8-4FE7-9321-21F5587E8177\prev_batch.cfg) do (
SET JOB=%a
SET USER=%b
SET TEMPLATE=%c
SET ASSETROOT=%d
SET SHAREADDR=%e
SET SHARENAME=%f
SET SHAREDRIVE=%g
SET SHAREUSER=%h
SET SHAREPASS=%i
)
C:\Windows\system32>(
SET JOB=99D0FAA9-22B8-4FE7-9321-21F5587E8177
SET USER=%b
SET TEMPLATE=%c
SET ASSETROOT=%d
SET SHAREADDR=%e
SET SHARENAME=%f
SET SHAREDRIVE=%g
SET SHAREUSER=%h
SET SHAREPASS=%i
)
try this:
FOR /F "usebackq tokens=1-9 delims=," %%a IN ("%ASSETROOT%\users\%USER%\%JOB%\prev_batch.cfg") do (
SET JOB=%%a
SET USER=%%b
SET TEMPLATE=%%c
SET ASSETROOT=%%d
SET SHAREADDR=%%e
SET SHARENAME=%%f
SET SHAREDRIVE=%%g
SET SHAREUSER=%%h
SET SHAREPASS=%%i
)
[addition by PW in response to supplementary question]
SET init=Y
SET "fields=JOB USER TEMPLATE ASSETROOT SHAREADDR SHARENAME SHAREDRIVE SHAREUSER SHAREPASS"
FOR /F "usebackq" %%a IN ("%ASSETROOT%\users\%USER%\%JOB%\prev_batch.cfg") do (
IF DEFINED init FOR %%i IN (%fields%) DO SET "%%i="
SET init=Y
FOR %%i IN (%fields%) DO IF DEFINED init IF NOT DEFINED %%i SET "%%i=%%a"&SET "init="
)
To read from sequential lines, the tokens and delims clauses are not required since there's only one string on each line BUT that one string needs to be applied to various variables.
Complicating the matter is the fact that variables that need to be set are used in the filename being read to set them.
Hence, the init flag is set non-empty initially; the variables are set once the first data line is read.
The next not-yet-set target variable is then set and the init flag cleared to ensure only one variable is set per line read.
okay, I like batch files and this one had me going for a while. You've told it that you only want %%a so that's what you're getting.
As Endoro said (I was typing the same answer when he posted), including the "tokens" keyword tells it which tokens you want.
Token %%a, obviously is the first, but by also telling the command processor that you want tokens 1-9 it separates and assigns them to next alphabetical 'variable'.
And in this case, usebackq is superfluous
There is another approach to solve this problem via an array of variable names. This method have the advantage that any modification to the list of variables (the number of variables, their names, their positions, etc) is made in a very easy way modifing just one line in the Batch file.
#echo off
setlocal EnableDelayedExpansion
rem Define the list of variable names
set variables=JOB USER TEMPLATE ASSETROOT SHAREADDR SHARENAME SHAREDRIVE SHAREUSER SHAREPASS
rem Convert the list into an array of variable names
set i=0
for %%a in (%variables%) do (
set /A i+=1
set variable[!i!]=%%a
)
set numVariables=%i%
:: Read all the arguments for this batch script from external text file
rem Version 1: Single line of text, tokens delimited with comma
set i=0
for /F "delims=" %%a in (%ASSETROOT%\users\%USER%\%JOB%\prev_batch.cfg) do (
for %%b in (%%a) do (
set /A i+=1
for %%i in (!i!) do set !variable[%%i]!=%%b
)
)
rem Version 2: Values of the variables on separate lines
set i=0
for /F "delims=" %%a in (%ASSETROOT%\users\%USER%\%JOB%\prev_batch.cfg) do (
set /A i+=1
for %%i in (!i!) do set !variable[%%i]!=%%a
)
rem Display values of all variables
for %%i in (1,1,%numVariables%) do (
for %%v in (!variable[%%i]!) do echo %%v = !%%v!
)
In the first version, the line of the file is read in %%a replaceable parameter and then processed in a for command this way:
for %%b in (%%a) do (
For example:
for %%b in (apples,oranges,bananas,grapes,strawberries) do (
Because standard Batch delimiters are space, comma, semicolon and equal-signs, the values in the list are processed one by one in the for (with NO /F option). This method allows to easily separate a list of values in individual tokens in a regular for command, but works only with the indicated delimiters.
Related
As in the question I am having trouble finding a good answer on how to extract values from a txt file into multiple variables, my plan for this is to incorporate saving into the game I mentioned in my previous question(I already have the values saving into the file I just need to be able to receive them back)
#echo off
set User=DNABuster
set /a Round=1
for /f "tokens=* delims=" %%x in (Save%User%.txt) do (
set a=%%x %0
set b=%%x %1
set c=%%x %2
set d=%%x %3
)
Is my current code(%0 is just a placeholder until I figure out how to get the first value alone to be equivalent to that variable), I also tried:
set User=DNABuster
set /a Round=1
set test=0
for /f "tokens=* delims=" %%x in (Save%User%.txt) do (
set /a test=%test%+1
set a.%test%=%%x
)
This answer I saw above a suggested answer was perfect for my problem:
Reserve a character (say, #) to be used as the first character of all of the variables you want to record.
so...
set #points=35
set action=3
set #money=22
To save all of the # variables, use
set #>filename
which would save #money and #points, but not action
To reload use
for /f "delims=" %%a in (filename) do set "%%a"
which will reload all of the variables saved in the file - which are, of course, only #variables. credit to Magoo for the post(I just copy pasted it to here for ease of access for new users)
I have a .txt file like this:
Customer Number||Customer Name||Partner Number||Partner Name||Customer Country
1ABC||Jame||1234||Anny||USA
2DEF||Susan||5678||Prissy||UK
My output should be a .csv file with no empty columns.
This is what I tried:
#echo off
setlocal disableDelayedExpansion
set input="C:\a.txt"
set output="C:\Customer_Pipe.csv"
>%output% (
for /f "tokens=*" %%a in ('input"') do (
set line=%%a
setlocal enableDelayedExpansion
echo "!line:|=","!">>"%~2"
)
)
If you want to read the file stored in variable INPUT, you need to read it as %INPUT% to do that (you stated INPUT literally, with odd quotation). When you specify '' within the set of for /F, the part within () is interpreted as a command rather than a file, so for /F tries to execute command input which cannot be found and so the script fails. I stringly recommend to put "" around the specified file, together with the usebackq option, in order to avoid trouble with white-spaces in paths/file names.
If you want to write into the file stored in variable OUTPUT, you must not redirect the echo to somewhere else (you placed >>"%~2" in the code).
Here is the code as I would write it:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define constants here:
set "INPUT=%~1"
set "OUTPUT=%~2"
if not defined INPUT exit /B 1
if not defined OUTPUT set "OUTPUT=con"
> "%OUTPUT%" (
for /F usebackq^ delims^=^ eol^= %%L in ("%INPUT%") do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
echo(!LINE:^|^|=,!
endlocal
)
)
endlocal
exit /B
The input file for the batch program must be provided as the first command line argument. The second argument (optional) is the output file.
Note that this script does not check whether the input data contains , characters, which impact the way the converted file is treated. If you want to put quotation marks around all fields of the returned CSV data to avoid data interpretation troubles, replace the above echo command line by:
echo("!LINE:||=","!"
The output data (with the original echo command line) looks like this:
Customer Number,Customer Name,Partner Number,Partner Name,Customer Country
1ABC,Jame,1234,Anny,USA
2DEF,Susan,5678,Prissy,UK
The output data with the modified echo command line looks like this:
"Customer Number","Customer Name","Partner Number","Partner Name","Customer Country"
"1ABC","Jame","1234","Anny","USA"
"2DEF","Susan","5678","Prissy","UK"
There are two problems in your code.
1)
You use setlocal EnableDelayedExpansion, that's a good idea, but you have to close it with endlocal else you get an error after ~32 setlocals.
2)
Your replace functions looks a bit odd.
You add some quotes, they will be part of the output later.
You could try this.
echo(!line:^|^|=,!
At all
>%output% (
for /f "tokens=*" %%a in (%input%) do (
set "line=%%a"
setlocal EnableDelayedExpansion
set "line=!line:||=,!"
(echo(!line!)
endlocal
)
)
I am very much a novice at Batch Scripting and i'm trying to write a simple script to READ from an INI file based on the Parameters that is passed when the batch file is called.
This is an example for what the INI file would look like:
[SETTING1]
Value1=Key1
Value2=Key2
Value3=Key3
[SETTING2]
Value1=Key1
Value2=Key2
Value3=Key3
[SETTING3]
Value1=Key1
Value2=Key2
Value3=Key3
I am running into a problem when it comes to reading ONLY the section that is called. It will read from any section that matches the "Value" and "Key" and i don't know how to limit it to only read the section with the settings.
The file is being called with this Parameter: run.bat run.ini setting2. My code below is what I have so far and I feel as if i have officially hit a wall. Can anyone help with this? Any help would greatly be appreciated.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET INIFile="%~f1"
for /f "usebackq delims=" %%a in (!INIFile!) do (
if %%a==[%2] (
SET yesMatch=%%a
for /f "tokens=1,2 delims==" %%a in (!yesMatch!) do (
if %%a==Value1 set Key1=%%b
if %%a==Value2 set Key2=%%b
if %%a==Value3 set Key3=%%b
)
ECHO !yesMatch!
ECHO !Key1!
ECHO !Key2!
ECHO !Key3!
pause
)
)
pause
exit /b
#ECHO OFF
SETLOCAL
SET INIFile="%~f1"
SET "FLAG="
for /f "usebackq tokens=1,*eol=|delims==" %%a in (%INIFile%) do (
IF "%%b"=="" (
REM No "=" so section
IF /i "%%a"=="[%2]" (SET flag=Y) ELSE (SET "flag=")
) ELSE IF defined flag (
REM data line - only if FLAG is defined
REM set values defined
SET "%%a=%%b"
REM pick particular values
if /i "%%a"=="Value1" set "Key1=%%b"
if /i "%%a"=="Value2" set "Key2=%%b"
if /i "%%a"=="Value3" set "Key3=%%b"
)
)
SET key
SET val
GOTO :EOF
Here's a way to get your values.
The data in the file is either [section] or name=value so settling delims to = will assign either section-only to %%a or name to %%a and value to %%b.
The flag is only set (defined) after its appropriate section is encountered, and cleared on the next section. Only of it is defined will the assignment take place.
The advantage of the simple set %%a=%%b is that it results in setting whatever values are defined in the section - no changes to the code need to take place if new values are added. Your original version has the advantage of picking particular values and setting only those. You pays your money, you takes your choice.
Note that the /i switch on an if statement makes the comparison case-insensitive.
Nota also the use of set "value=string" which ensures that trailing spaces on a line are not included in the value assigned.
edit : By default, the end of line character is ; so any line starting ; is ignored by for/f. The consequence is that the values for the ;-commented-out section would override the values set for the previous section.
Setting eol to | should cure the problem. It really doesn't matter what eol is set to; it's exactly one character which may not appear anywhere in the INI-file (else that line would appear truncated.)
It is possible, if necessary, to set eol to control-Z but selecting an unused character is easier...
Consequently, a one-line change - the eol parameter is included in the for /f options.
So, I was writing a small batch-file game, and came across this problem in the FOR loop.
This is a small chunk of my code.
If the player picks-up the rock, check if it is on the table, then put it in your pack.
The problem is the SET command doesn't work.
I guess that lines executes as : set %table1%=empty not : set table1=empty.
I feel like there is a simple solution to this problem, I've trying for a few days in my spare time, but haven't gotten it.
Any help is appreciated!
set take=rock
set table1=box
set table2=rock
set table3=wrench
for %%x in (%table1% %table2% %table3%) do (
if %%x==%take% (
set %%x=empty
set pack=%%x
goto tableRoom
)
)
The main problem with your code is set %%x=empty for a logical reason: the for loop is iterating over the list of the values inside the table variables, not over the name of the variables so you can not change the value of the variable when you don't have a reference to the variable, you have the value inside it.
Enabling delayed expansion and iterating over the names of the variables can solve the problem
#echo off
setlocal enableextensions enabledelayedexpansion
set "take=rock"
set "table1=box"
set "table2=rock"
set "table3=wrench"
for %%x in (table1 table2 table3) do (
if "!%%x!"=="%take%" (
set "%%x=empty"
set "pack=%take%"
goto tableRoom
)
)
:tableRoom
set table
exit /b
%%x will hold the name of the variable, so when !%%x! is executed it will be something like !table1!, retrieving the value inside the variable (when delayed expansion is enabled).
If the names of the used variables (table...) does not collide with anything else, and you don't want to use delayed expansion, it is possible to take the output of set table command (the list the variables with its values) and process this list with a for /f command, splitting the command output, separating variable name and value
#echo off
setlocal enableextensions disabledelayedexpansion
set "take=rock"
set "table1=box"
set "table2=rock"
set "table3=wrench"
for /f "tokens=1,* delims==" %%a in ('set table') do (
if "%%b"=="%take%" (
set "%%a=empty"
set "pack=%take%"
goto tableRoom
)
)
:tableRoom
set table
exit /b
The output of set command contains var=value. Each of the lines is splitted using the = as a delimiter to get two tokens (tokens=1,*). %%a will hold the first token (the variable name) and %%b the rest of the line (the value in the variable)
You can use a counter to now which table you're testing in your FOR loop and
set directly the table!N! as empty :
set take=rock
set table1=box
set table2=rock
set table3=wrench
setlocal enabledelayedexpansion
set $c=1
for %%x in (%table1% %table2% %table3%) do (
if %%x==%take% (
set table!$c!=empty
set pack=%%x
goto tableRoom
)
set /a $c+=1
)
:tableroom
echo table2 is now : %table2%
I have a text file with the names of computer names and corresponding static i.p. addresses in the following format.
COMPUTER NAME:PC ADDRESS=154.100.1.1 MASK=255.255.254.0
COMPUTER NAME:PC2 ADDRESS=100.100.1.1 MASK=255.255.254.0
I would like to take the values from each line and put them as variables in a batch file for use later. Is this possible? The overall goal is to have the values from this easily edited text file to be used in netsh commands in another batch file.
I've looked around and found ways to take lines of a text file and place them in one variable using the snippet below. However, I do not know how to create multiple variables from one line. If someone could help me with this I'd greatly appreciate it!
#echo o
setlocal enabledelayedexpansion
set Counter=1
for /f %%x in (D:\COMP_T.txt) do (
set "comp!Counter!=%%x"
set /a Counter+=1
)
This should work:
#echo off
setlocal EnableDelayedExpansion
set "Count=1"
for /f "tokens=1,2,3,4,5,6,7 delims==: " %%A in (C:\File.txt) do (
set "%%A[!Count!]=%%C"
set "%%D[!Count!]=%%E"
set "%%F[!Count!]=%%G"
set /a "Count+=1"
)
:: Call other batch script here.
endlocal
Example Output:
COMPUTER[1]=PC
COMPUTER[2]=PC2
ADDRESS[1]=154.100.1.1
ADDRESS[2]=100.100.1.1
MASK[1]=255.255.254.0
MASK[2]=255.255.254.0
Here is a solution that avoids the need for delayed expansion. It uses FINDSTR to insert a line number followed by : at the beginning of each line. The search string of "^" is guaranteed to match every line in the file.
The only other issue is to set TOKENS and DELIMS to parse the line properly.
#echo off
setlocal
for /f "tokens=1,4,6,8 delims=:= " %%A in ('findstr /n "^" "d:\comp_t.txt"') do (
set "comp%%A=%%B"
set "addr%%A=%%C"
set "mask%%A=%%D"
set "counter=%%A"
)
To use the set of variables in another batch file, line by line, just parse the lines as done in other answers here, and call the other batch file with the metavariables.
#echo off
for /f "tokens=1,2,3,4,5,6,7 delims==: " %%a in ('type "File.txt" ') do (
echo "computer_name=%%c"
echo "address=%%e"
echo "mask=%%g"
Call "batch script" "%%c" "%%e" "%%g"
)