Structured Array in Powershell batch file adds extra space - arrays

I have a batch file that contains a structured array. The problem is that it is adding a space to the end of the variable. The code below will output:
Name=Joe zzzzzz
Value=1 zzzzzz
...
Where is the space after the name and value coming from, and how can I get rid of it?
Thanks!
#echo off
set len=3
set obj[0].Name=Joe
set obj[0].ID=1
set obj[1].Name=Mark
set obj[1].ID=2
set obj[2].Name=Mohan
set obj[2].ID=3
set i=0
:loop
if %i% equ %len% goto :eof
set cur.Name=
set cur.ID=
for /f "delims==. tokens=1-3" %%j in ('set obj[%i%]') do (
set cur.%%k=%%l
)
echo Name=%cur.Name%zzzzzz
echo Value=%cur.ID%zzzzzz
set /a i=%i%+1
goto loop

Related

Windows Batch read a file, parse and output

I'm 90% of the way there on a Windows Batch file.
It takes 2 input parameters, input and output files.
It then reads in the input file, and substrings certain lines into arrays (Well line 2 onwards).
Then we come to a loop for outputting.
With delayed expansion on my counter for going through the array doesn't update unless I use !counter2!, %counter2% doesn't work.
Using !arrayname[!counter2!]! doesn't work.
Here is the code as it stands.
#Echo off
if [%1] == [] goto usage
if [%2] == [] goto usage
echo start time : %time%>logfile.log
set input_file=%1
set output_file=%2
if exist %output_file% del %output_file%
Echo Start reading %input_file%>> logfile.log
setLocal EnableDelayedExpansion
set /a counter=1
for /F "tokens=* delims=" %%a in ('type %input_file%') DO (
::echo !counter!
if "!counter!"=="1" set header=%%a
if not "!counter!"=="1" (
set data[!counter!]=%%a
set line=%%a
set jobnumber[!counter!]=!line:~0,7!
set docnumber[!counter!]=!line:~7,5!
set pagecount[!counter!]=!line:~12,2!
set customernumber[!counter!]=!line:~14,20!
set presort[!counter!]=0000
set postcode[!counter!]=0000
set inserts[!counter!]=!line:~36,11!
set filler[!counter!]=000000
set address[!counter!]=!line:~58,350!
set filler2[!counter!]=" "
set endline[!counter!]=X
)
set /a counter=counter+1
)
Echo Start writing %output_file%>> logfile.log
for /L %%G in (2,1,%counter%) DO (
set counter2=%%G
echo !counter2!
echo !jobnumber[%counter2%]!!docnumber[%counter2%]!!pagecount[%counter2%]!!customernumber[%counter2%]!!presort[%counter2%]!!postcode[%counter2%]!!inserts[%counter2%]!!filler[%counter2%]!!address[%counter2%]!!filler2[%counter2%]!!endline[%counter2%]!>>%output_file%
)
echo end time : %time%>>logfile.log
pause
goto :eof
:usage
echo Usage: blah.bat input_filename output_filename
pause
goto :eof
It is the echo !jobnumber[%counter2%]! where things are not being resolved.
The echo !counter2! works fine.
Before you ask, Yes I know this could be done better and easier in C# or another programming language, However I am tasked with doing it in a windows batch file.
Thanks in advance for any help provided.
Tel
Try with:
for /L %%G in (2,1,%counter%) DO (
set counter2=%%G
echo !counter2!
echo !jobnumber[%%G]!!docnumber[%%G]!!pagecount[%%G]!!customernumber[%%G]!!presort[%%G]!!postcode[%%G]!!inserts[%%G]!!filler[%%G]!!address[%%G]!!filler2[%%G]!!endline[%%G]!>>%output_file%
)
You are not changing the value of the coutner2 so you don't need it and you can directly use %%G.
Though if you need changes in counter2 you'll have to wrap it again in for loop and to use its tokens.

batch script to add number to a string in loop

i need to generate list of dummy users. no of users will be provided as a input.. like 5 or 500 or 5000.
all i want is to have a standard text like usr and append a number and generate the list like usr1, usr2, usr3 etc. I thought i can do this in batch file quickly. but stuck with loop and appending the number to the string.. can some help?
#echo OFF
SETLOCAL ENABLEDELAYEDEXPANSION
set /p numb="Enter how many users to be generated "
set numb2=0
set x=0
set name1=tstusr
set name1=tstusr
set name2=%name1%
for /l %%x in (1,1,%numb%) do (
echo %%x
set numb2=%%x
set name1=tstusr
set name2=%name1%%numb2%
echo %name1%
echo %name2%
)
with a slight modification of your code...
#echo OFF
SETLOCAL ENABLEDELAYEDEXPANSION
set /p numb="Enter how many users to be generated "
set numb2=0
set x=0
set name1=tstusr
set name1=tstusr
set name2=%name1%
for /l %%x in (1,1,%numb%) do (
echo %%x
set numb2=%%x
set name1=tstusr
set name2=!name1!!numb2!
echo !name1!
echo !name2!
)
endlocal
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
set /p numb="Enter how many users to be generated "
>q28342811.txt ECHO tstusr%random%
:loop
set "name=tstusr%random%"
FINDSTR /x "%name%" q28342811.txt >NUL
IF ERRORLEVEL 1 SET /a numb -=1&>>q28342811.txt ECHO %name%
IF %numb% gtr 1 GOTO loop
TYPE q28342811.txt
GOTO :EOF
Produces q28342811.txt
generate a random username to the output file, then repeat the operation numb-1 times, checking that the new candidate doesn't already exist in the file first.

Batch Roguelike Game

I've been learning some batch programming, and decided to make a roguelike, as it's one of my favorite types of games. I have researched any information on making a roguelike in batch, but haven't found much. From the little bit I've gathered, this is the code I have so far:
#echo off
rem init starting position
set pos=6
:level
set c1=#
set c2=#
set c3=#
set c4=#
set c5=#
set c6=.
set c7=.
set c8=#
set c9=#
set c10=.
set c11=.
set c12=#
set c13=#
set c14=#
set c15=#
set c16=#
echo %c1%%c2%%c3%%c4%
echo %c5%%c6%%c7%%c8%
echo %c9%%c10%%c11%%c12%
echo %c13%%c14%%c15%%c16%
This works so far, and draws the simple 4x4 room.I made the room only 4x4 for testing purposes, so it would be simple.
Now I'm at a point where I'm not sure how to write the rest. I know I'll need to call subroutines, and get the input (WASD), but I don't know how to structure those subroutines in the file. I'd appreciate anyone's help on how to structure a batch roguelike, get input to move the player, or even just ideas about what could work.
Thanks.
I give you here a technic without CHOICE and without an External command.
It use Xcopy to get the INPUT (W,A,S,D). IN this Exemple i don't make any test of position (where is your object on the screen), So to test it go first right (D).
It's just an exemple to help you.
#echo off
:level
set c1=#
set c2=#
set c3=#
set c4=#
set c5=#
set c6=.
set c7=.
set c8=#
set c9=#
set c10=.
set c11=.
set c12=#
set c13=#
set c14=#
set c15=#
set c16=#
#echo off
setlocal enableextensions enabledelayedexpansion
set haut=
set larg=
:boucle
cls
echo WASD TO MOVE THE CURSOR Q TO QUIT&echo.
for %%a in ( !haut! ) do echo.
call:aff
Set "Key="
For /F "delims=" %%# In ('Xcopy /W "%~f0" "%~f0" 2^>Nul') Do If Not Defined Key Set "Key=%%#"
Set "Key=%Key:~-1%"
if /i %key%==q (exit /b)
if /i %key%==w goto:UP
if /i %key%==s goto:DOWN
if /i %key%==a goto:LEFT
if /i %key%==d goto:RIGHT
:LEFT
set larg=!larg:~0,-1!
goto boucle
:RIGHT
set larg= !larg!
goto boucle
:UP
set haut=!haut:~0,-2!
goto boucle
:DOWN
set haut=!haut! a
goto boucle
:aff
echo !larg!%c1%%c2%%c3%%c4%
echo !larg!%c5%%c6%%c7%%c8%
echo !larg!%c9%%c10%%c11%%c12%
echo !larg!%c13%%c14%%c15%%c16%
#ECHO OFF
setlocal enableextensions enabledelayedexpansion
SET /a maxx=13
SET /a maxy=7
SET /a level=1
:: current x,y position in cx, cy - set start position
SET /a cx=3
SET /a cy=2
SET objdesc16=*Book of something
CALL :putobjects 1 6 3 16
SET userprompt=Q always Quits - MOVE WASD
SET moveoptions=wasd
:newlevel
:: Set physical map
CALL :map%level%
:loop
CALL :showmap
CALL :getmove
IF /i "%key%"=="Q" GOTO :eof
CALL :makemove
GOTO loop
:getmove
ECHO(%userprompt%
SET "userprompt="
:getmovel
Set "key="
For /F "delims=" %%Z In ('Xcopy /W "%~f0" "%~f0" 2^>Nul') Do If Not Defined Key Set "key=%%Z"
IF NOT DEFINED key GOTO getmovel
Set "key=%key:~-1%"
IF /i "%key%"=="Q" GOTO :eof
IF /i "%moveoptions%"=="!moveoptions:%key%=!" GOTO getmovel
GOTO :eof
:: make a move given KEY
:makemove
if /i %key%==w CALL :movedir 0 -1
if /i %key%==a CALL :movedir -1 0
if /i %key%==s CALL :movedir 0 1
if /i %key%==d CALL :movedir 1 0
GOTO :eof
:movedir
SET /a $m=%1+%cx%
SET /a $n=%2+%cy%
CALL :mapsquare %$m% %$n%
IF "%$s%"=="." SET cy=%$n%&SET cx=%$m%&CALL :setprompt wasd&GOTO :EOF
IF "%$s%"=="#" CALL :setprompt ouch&GOTO :EOF
GOTO :eof
:: standard userprompts
:setprompt
IF /i "%1"=="wasd" SET userprompt=MOVE WASD&GOTO :EOF
IF /i "%1"=="ouch" SET userprompt=OUCH!&GOTO :EOF
GOTO :EOF
:map1
CALL :initmap
:: Special map symbols for level 1 (stairs, etc)
CALL :mapsymbol 4 2 ?
GOTO :eof
:mapsymbol
SET "c_%1_%2=%3"
GOTO :eof
:: set border to '#', internal to '.'
:initmap
FOR /l %%y IN (0,1,%maxy%) DO (
FOR /l %%x IN (0,1,%maxx%) DO (
SET c_%%x_%%y=.
IF %%x==0 SET c_%%x_%%y=#
IF %%y==0 SET c_%%x_%%y=#
IF %%x==%maxx% SET c_%%x_%%y=#
IF %%y==%maxy% SET c_%%x_%%y=#
)
)
GOTO :eof
:: map on new screen
:showmap
CLS
FOR /l %%y IN (0,1,%maxy%) DO (
SET "mapline="
FOR /l %%x IN (0,1,%maxx%) DO (
CALL :mapsquare %%x %%y
SET mapline=!mapline!!$s!
)
ECHO(!mapline!
)
GOTO :eof
:: get the symbol to show in x,y
:mapsquare
:: From map
SET $s=!c_%1_%2!
:: Object
IF DEFINED obj%level%_%1_%2 CALL :getobj %level%_%1_%2
:: Character
IF %cx%==%1 IF %cy%==%2 SET $s=#
SET $s=%$s:~0,1%
GOTO :eof
:: Get object description for object (%1) to $s
:getobj
SET $s=!obj%1!
SET $s=!objdesc%$s%!
GOTO :eof
:: PUTOBJECTS onlevel at-x at-y object#
:putobjects 1 1 3 16
SET "obj%1_%2_%3=%4"
GOTO :eof
This code may be useful.
The main loop simply repeats showmap, getmove, makemove.
makemove is the critical routine that needs to be expanded to build your game. The principle is to see which moves are valid for the next input, place those in moveoptions and generate an appropriate userprompt
Otherwise, your mapcells are in c_x_y and objects in obj_level_x_y I simply chose the object-description to be displaysymbolDESCRIPTION in objdescX where the X is stored in obj_level_x_y. In this way, you can set up extra object characteristics simply by setting variables like objhitbonusX or objdosesX.
You could extend the scheme to opponenthealthX opponentweaponX etc.
You'd not that GOTOs are minimised to avoid spaghetti-code.

how to concat all values of for loop in one variable in batch script

I'm giving user options to select certain properties on command line. User want to select comma separated list. So user will see something like this
Prop1
Prop2
Prop3
So user can give 1,3 and hit enter and user will get 1 and 3 databases created.
But these Prop1, Prop2, Prop3 has unique names and ids, which I've given in same batch script as properties and I want to concat all those depending on options user has selected and pass to my build script.
Example of properties:
SET propertyID1=11
SET propertyID2=12
SET propertyID3=13
SET propertyID4=14
SET propertyID5=15
SET propertyIDPref1=011
SET propertyIDPref2=012
SET propertyIDPref3=013
SET propertyIDPref4=014
SET propertyIDPref4=015
SET propertyName1=A
SET propertyName2=B
SET propertyName3=C
SET propertyName4=D
SET propertyName5=E
call :parse "%M%"
pause
goto :eof
:parse
setlocal
set list=%~1
for /F "tokens=1* delims=," %%f in ("%list%") do (
if not "%%f" == "" call :getLineNumber %%f
if not "%%g" == "" call :parse "%%g"
if "%%g" == "" call :printPropertiesConcatenation
)
endlocal
goto :eof
:printPropertiesConcatenation
setLocal
echo "Gr8 " %buildPropertiesList%
endLocal
goto :eof
:getLineNumber
setlocal
echo file name is %1
set propID = 'propertyID'%1%
set propStr=propertyID
set propID=%1
set newvar=!%propStr%%propID%!
echo %newvar%
set propNameStr=propertyName
set propName=!%propNameStr%%propID%!
echo %propName%
set propIDPrefix=propertyIDPref
set propIDPrefixWithPrefix=!%propIDPrefix%%propID%!
echo %propIDPrefixWithPrefix%
set buildPropertiesList=%buildPropertiesList%','!%propIDPrefix%%propID%!
goto :eof
I can read correct values from these properties on iteration and see it using echo in loop.
But I want to concat these values and pass it to build script. But I don't get way to see all concatenated values in one variable.
I want something like this.
set propNames = A,C and set propIds = 11,13 in the end so that I can pass propNames and PropIds.
From above code I want buildPropertiesList to have 011,013
Is there any way
this might work for you:
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
SET propertyID1=11
SET propertyID2=12
SET propertyID3=13
SET propertyID4=14
SET propertyID5=15
SET propertyIDPref1=011
SET propertyIDPref2=012
SET propertyIDPref3=013
SET propertyIDPref4=014
SET propertyIDPref4=015
SET propertyName1=A
SET propertyName2=B
SET propertyName3=C
SET propertyName4=D
SET propertyName5=E
for /f "tokens=1*delims==" %%a in ('set "property"') do (
set "apx=%%a"
set "apx=!apx:*property=!"
for /f "delims=0123456789" %%b in ("!apx!") do set "apx=%%b"
if defined props!apx! (
call set "props!apx!=%%props!apx!%%,%%b"
) else (
set "props!apx!=%%b"
)
)
set "props"
You may solve this problem with less code with the aid of arrays. For example:
#echo off
setlocal EnableDelayedExpansion
rem Create the arrays of properties:
set /A i=1, ID=11, IDPref=1011
for %%a in (A B C D E) do (
SET propertyID[!i!]=!ID!
SET propertyIDPref[!i!]=!IDPref:~-3!
SET propertyName[!i!]=%%a
set /A i+=1, ID+=1, IDPref+=1
)
echo Properties menu:
echo/
for /L %%i in (1,1,5) do echo %%i. !propertyName[%%i]!
echo/
set /P "M=Enter properties list: "
call :parse "%M%"
echo Names: !propNames:~0,-1!
echo Ids: !propIds:~0,-1!
echo List: !propList:~0,-1!
pause
goto :eof
:parse
set "propNames="
set "propIds="
set "propList="
for %%i in (%~1) do (
set "propNames=!propNames!!propertyName[%%i]!,"
set "propIds=!propIds!!propertyID[%%i]!,"
set "propList=!propList!!propertyIDPref[%%i]!,"
)
exit /B

Batch File to Extract values when variable names change in each file

OK, I have hundred of files that have a text header in them that includes one or more entries for a set of eight different variables (name, host, year, month, hour, minute, second). The first time the value is displayed it looks like:
#name 4 10
3 4 DHARLAN
Every time after this (and the variable sets can appear 1 to 100 times per file) it shows up only as:
3 4 DHARLAN
The problem comes in that what happens to be a 4 in this case can be any value between 1 & 99. So in the next file it might be:
3 15 DHARLAN
So really the of eavh variables entries are something like:
3 ## <value>
Where ## is determined earlier in the header by:
#name ## X
I don't understand enoyugh about how FOR /F TOKENS works to get anything that comes close.
What I need is to parse a directory and end up with a file something like:
<filenameA> <name1> <host1> <year1> <month1> <day1> <hour1> <minute1> <second1>
<filenameA> <name2> <host2> <year2> <month2> <day2> <hour2> <minute2> <second2>
<filenameB> <name1> <host1> <year1> <month1> <day1> <hour1> <minute1> <second1>
...
What I have so far:
FOR /f "tokens=*" %%i IN ('dir /a-d /s /b') DO call :findfile "%%i"
:findfile
REM Print Filename
FINDSTR /B /M "#UGC">>output.txt
REM set Name Variable, need 2nd word (7th & if exists (8th) character) from this line only
FINDSTR /B "#name">%%n
REM Find all lines with name variable
FINDSTR /B "3 %n%">>output.txt
Help is greatly appreciated, even suggestions to a program that can do this.
Thoughts
So...This is how I read your question. You have many files with many values and for each file you want output a single line of all the file's variables. Each variable is composed of two lines. 1. The variable declaration (name) and 2. The variable value (DHARLAN). These lines are associated by a number (1 to 99). Is this correct?
This should get you started...
#echo off
setlocal EnableExtensions EnableDelayedExpansion
<nul set /p "=">output.txt
for /f "delims=" %%F in ('dir /a:-d /b /s') do if exist "%%~fF" (
set "name="
set "namenum="
set "host="
set "hostnum="
set "year="
set "yearnum="
set "month="
set "day="
set "daynum="
set "monthnum="
set "hour="
set "hournum="
set "minute="
set "minutenum="
set "second="
set "secondnum="
set "count=0"
for /f "usebackq delims=" %%L in ("%%~fF") do (
for /f "tokens=1,2,3*" %%X in ("%%L") do (
if "%%Y"=="!namenum!" set "name=%%Z" & set /a "count+=1"
if "%%Y"=="!hostnum!" set "host=%%Z" & set /a "count+=2"
if "%%Y"=="!yearnum!" set "year=%%Z" & set /a "count+=4"
if "%%Y"=="!monthnum!" set "month=%%Z" & set /a "count+=8"
if "%%Y"=="!daynum!" set "day=%%Z" & set /a "count+=16"
if "%%Y"=="!hournum!" set "hour=%%Z" & set /a "count+=32"
if "%%Y"=="!minutenum!" set "minute=%%Z" & set /a "count+=64"
if "%%Y"=="!secondnum!" set "second=%%Z" & set /a "count+=128"
if /i "%%X"=="#name" set "namenum=%%Y"
if /i "%%X"=="#host" set "hostnum=%%Y"
if /i "%%X"=="#year" set "yearnum=%%Y"
if /i "%%X"=="#month" set "monthnum=%%Y"
if /i "%%X"=="#day" set "daynum=%%Y"
if /i "%%X"=="#hour" set "hournum=%%Y"
if /i "%%X"=="#minute" set "minutenum=%%Y"
if /i "%%X"=="#second" set "secondnum=%%Y"
if "!count!" equ "255" (
echo %%~nxF !name! !host! !year! !month! !day! !hour! !minute! !second!>>output.txt
set "name="
set "namenum="
set "host="
set "hostnum="
set "year="
set "yearnum="
set "month="
set "day="
set "daynum="
set "monthnum="
set "hour="
set "hournum="
set "minute="
set "minutenum="
set "second="
set "secondnum="
set "count=0"
)
)
)
)
goto :eof
:End
endlocal
Update
Here is an updated version of the script above with comments. It should also address your comment below with the setup section and the cd command.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
:: Setup
set "ResultsFolder=results"
set "ExportFile=output.txt"
:: Set the Working Directory
cd data
:: Verify that the Results folder exists
if not exist "%ResultsFolder%\*" md "%ResultsFolder%"
set "OutputFile=%ResultsFolder%\%ExportFile%"
:: Empty the results file.
<nul set /p "=">%OutputFile%
:: Loop through the files /a:-d in the directory and its subdirectories /s.
for /f "delims=" %%F in ('dir /a:-d /b /s') do if exist "%%~fF" (
call :Reset
rem Loop through the file contents and parse each line.
for /f "usebackq delims=" %%L in ("%%~fF") do (
for /f "tokens=1,2,3*" %%X in ("%%L") do (
rem Keep track of the variables.
if "%%Y"=="!namenum!" set "name=%%Z" & set /a "count+=1"
if "%%Y"=="!hostnum!" set "host=%%Z" & set /a "count+=2"
if "%%Y"=="!yearnum!" set "year=%%Z" & set /a "count+=4"
if "%%Y"=="!monthnum!" set "month=%%Z" & set /a "count+=8"
if "%%Y"=="!daynum!" set "day=%%Z" & set /a "count+=16"
if "%%Y"=="!hournum!" set "hour=%%Z" & set /a "count+=32"
if "%%Y"=="!minutenum!" set "minute=%%Z" & set /a "count+=64"
if "%%Y"=="!secondnum!" set "second=%%Z" & set /a "count+=128"
if /i "%%X"=="#name" set "namenum=%%Y"
if /i "%%X"=="#host" set "hostnum=%%Y"
if /i "%%X"=="#year" set "yearnum=%%Y"
if /i "%%X"=="#month" set "monthnum=%%Y"
if /i "%%X"=="#day" set "daynum=%%Y"
if /i "%%X"=="#hour" set "hournum=%%Y"
if /i "%%X"=="#minute" set "minutenum=%%Y"
if /i "%%X"=="#second" set "secondnum=%%Y"
rem When a full set is reached print it out.
if "!count!" equ "255" (
echo %%~nxF !name! !host! !year! !month! !day! !hour! !minute! !second!>>%OutputFile%
call :Reset
)
if "!count!" gtr "255" (
echo %%~nxF: Incomplete Set Encountered. Stopping parsing of this file, continuing to the next.
rem You can also use other validations to identify incomplete sets.
)
)
)
)
goto :eof
:: Reset all of the variables for the next set.
:Reset
set "name="
set "namenum="
set "host="
set "hostnum="
set "year="
set "yearnum="
set "day="
set "daynum="
set "month="
set "monthnum="
set "hour="
set "hournum="
set "minute="
set "minutenum="
set "second="
set "secondnum="
set "count=0"
goto :eof
:End
endlocal
Summary
This is a summary of what the script is doing and how it works.
The Main for loop, will loop through all files located within the current working directory. dir /a:-d /b /s
Inside this loop, we first setup the variables needed to keep track of the file variables. :Reset
The next for loop will open the file and read each line of the file. %%L
The third for loop will then parse the line for the relevant variable information. Retrieve the first, second, and all remaining tokens from the line (1,2,*) into variables (%%X, %%Y, %%Z)
Now perform logic to keep track of the variables sets. If the variable number has been set and this line matches the variable number, then save the variable value. Else if the variable name matches, retrieve the variable number for comparison on the following lines.
Also increment the set count number and when a full set has been discovered, write it to the output file with the filename.
Reset the variables for use with the next set.
If the count does not equal 255, the file is incorrectly formatted or has an incomplete set of variables.
Notes
This script is just what seems to be the best solution for the questions presented and the information provided therein. I have had to make assumptions about the files being processed and therefore may requires some modifications. If you want to show us a full examples of the file to be parsed, it would help in determining what to do.

Resources