Increase number in string in bat file? - windows

How can I increment the value of an int in a string ?
Say I have foo-815-bar. I'd like to have foo-815-bar.
foo and bar can be constants (although if bar can be an unknown variable, it would be preferable), and 815 is a variable. It's a 3 digit number that is to be incremented, so that foo-123-bar would return foo-124-bar.

Example:
#echo off
set "string=foo-123-bar"
for /f "tokens=1-3 delims=-" %%i in ("%string%") do (
set "pre=%%i"
set /a number=%%j+1
set "post=%%k"
)
set "string=%pre%-%number%-%post%"
echo %string%
.. output is:
foo-124-bar

This should get you started... you might have to place this inside a loop depending on your needs.
#echo off
set myFoo=foo-
set myBar=-bar
set /a myIncrementor=123
echo %myFoo%%myIncrementor%%myBar%
set /a myIncrementor+=1
echo %myFoo%%myIncrementor%%myBar%

Related

Batch for loop find string in variable

I want to find the string A in the variable Code=AAABASDG
and count each time 1 up if "A" was found so the result should be that it outputs 4 because in Code variable there are 4 A's
Example Code :
#echo off
set /A C=0
set Code=AAABASDG
for %%i in (%Code%) do IF "%%i"=="A" set /A C=%C%+1
echo %C%
pause
You could get the length of original string A, then delete the "A" letters from the string and get the length of the result, to finally subtract both lengths.
To easily get the length of the string, you could store it in a file and then ask for the %%~Z size of the file. Here it is:
#echo off
setlocal
set "Code=AAABASDG"
> before.txt echo %code%
> after.txt echo %code:A=%
for %%b in (before.txt) do for %%a in (after.txt) do set /A "count=%%~Zb-%%~Za"
echo %count%
The only drawback of this method is that it is not case-aware: both upcase and lowcase letters are delete in the replacement operation
#echo off
set /A C=0
set "Code=AAABASDG"
:loop
if defined code (
if "%code:~-1%"=="A" set /a C+=1
set "code=%code:~0,-1%"
goto loop
)
echo %C%
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier.
Substrings in batch are obtained from %var:~m,n% where ,n is optional; m is count-of-chars-from-beginning-of-string, from end if negative. ,n positive = max length to return; negative = end-position in chars from end; missing=return all after m
Here's a quick example which gets help from PowerShell:
#Echo Off
SetLocal EnableExtensions
Set "Code=AAABASDG"
For /F %%G In ('%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe
-NoProfile "[RegEx]::Matches('%Code%','A').Count"') Do Set "C=%%G"
Echo(%C%
Pause

Windows Batch SET with Variable Substring Length?

Take this simple example:
#ECHO OFF
SET /P phrase="Enter Word : "
SET /a rnum=%random% %%10 +1
ECHO %phrase%
ECHO %rnum%
SET rchar=%phrase:~0,%rnum%%
ECHO %rchar%
Pause
I just want to be able to pass that rnum variable to pick that as the character chosen from the left of that user entered word to that random character.
I can't seem to figure out how to pass that as a variable.
I tried with enabledelayedexpansion with no luck:
#ECHO OFF
SET /P Phrase="Enter Word : "
SET /a rnum=%random% %%10 +1
ECHO %phrase%
ECHO %rnum%
setlocal enabledelayedexpansion
SET rchar=!phrase:~0,%rnum%!
endlocal
ECHO %rchar%
Pause
So how do I pass rnum as a variable in this instance? Thanks for any assistance.
Here's a simple modification of your example delayed expansion code, which shows one method of maintaining your variable value beyond endlocal:
#ECHO OFF
SET /P "phrase=Enter Word : "
SET /A rnum = %RANDOM% %% 10 + 1
ECHO %phrase%
ECHO %rnum%
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%G IN ("!phrase:~0,%rnum%!") DO ENDLOCAL & SET "rchar=%%~G"
ECHO rchar=%rchar%
PAUSE
The above example should be fine, as long as the end user does not begin to input strings with problematic characters. If you wanted to make it a little more robust for such scenarios then perhaps this will help:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
:AskString
Rem Get interactive string input
Set "String="
Set /P String="Enter Word : "
If Not Defined String GoTo AskString
Set String
Rem Generate a random integer 1..10
Set /A "Integer = (%RANDOM% %% 10) + 1"
Set Integer
Rem Create a substring variable using %String% and %Integer%
Echo %%SubString%% = %%String:~0,%Integer%%%
SetLocal EnableDelayedExpansion
For /F Delims^=^ EOL^=^ UseBackQ %%G In ('"!String:~0,%Integer%!"') Do (
EndLocal
Set "SubString=%%~G"
)
Set SubString
Pause
Please note that the above code uses Set Variable to display the variable name along side its value. If your variable contains certain poison characters just using Echo %Variable% may not work, and you would probably be better off keeping delayed expansion enabled at that time.
As Compo already comments, the position of your endlocal is the problem.
You could just move the endlocal after the echo
#ECHO OFF
setlocal enabledelayedexpansion
SET /P Phrase="Enter Word : "
SET /a rnum=%random% %%10 +1
ECHO !phrase!
ECHO !rnum!
SET "rchar=!phrase:~0,%rnum%!"
ECHO !rchar!
endlocal

Aligning output from batch file For loop

REM ************************ HIGH SCORES TABLE
**********************************************
:highscorestable
set /a count = 0
for /f "tokens=1,2,3 delims=-" %%i in (highscores.txt) do (
set hs=%%i
set hsn=%%j
set hsv=%%k
set hst=%%jscored %%iusing%%k
set hsn1=!hsn!
set hsv1=!hsv!
set hs1=!hs!
set hsn1= %hsn1%
set hsv1= %hsv1%
set hs1= %hs1%
echo %hsn1:~-15% %hsv1:~-15% %hs1:~-15%
set /a count+=1
if "!count!"=="5" goto :end
)
:end
echo.
pause
I'm pulling the first 5 lines from a text file using a For loop. My variables populate fine, however I'm struggling with the required alignment.
My ultimate end result should be:
James Commitment 300
Markos Excellence 290
Jeremy Si Party 50
What obvious thing am I missing here?
You could try this:
SetLocal EnableDelayedExpansion
REM **************************** HIGH SCORES TABLE ****************************
:highscorestable
Set "count=0"
For /F "UseBackQTokens=1-3Delims=-" %%i In ("highscores.txt") Do (
Set "hs=%%i"
Set "hsn=%%j"
Set "hsv=%%k"
Set "hst=%%jscored %%iusing%%k"
Set "hs= %%i "
Set "hsn1=%%j "
Set "hsv1=%%k "
Echo !hsn1:~,15!!hsv1:~,15!!hs:~-15!
Set/A count+=1
If "!count!"=="5" GoTo :end
)
:end
Echo(
Pause
Or without the possibly unnecessary variables:
SetLocal EnableDelayedExpansion
REM **************************** HIGH SCORES TABLE ****************************
:highscorestable
Set "count=0"
For /F "UseBackQTokens=1-3Delims=-" %%i In ("highscores.txt") Do (
Set "hs= %%i "
Set "hsn=%%j "
Set "hsv=%%k "
Set "hst=%%jscored %%iusing%%k"
Echo !hsn:~,15!!hsv:~,15!!hs:~-15!
Set/A count+=1
If "!count!"=="5" GoTo :end
)
:end
Echo(
Pause
In both cases, I've added the necessary SetLocal EnableDelayedExpansion line just in case it isn't in your script prior to your provided code.
Edit
You can also alter the code a little forego delayed expansion: (my preferred option)
REM **************************** HIGH SCORES TABLE ****************************
:highscorestable
For /F "Tokens=1-4Delims=:-" %%A In ('FindStr/N $ "highscores.txt"'
) Do If %%A LEq 5 (Set "hst=%%Cscored %%Busing%%D"
Set "hss= %%B"
Set "hsn=%%C "
Set "hsv=%%D "
Call Echo %%hsn:~,15%%%%hsv:~,15%%%%hss:~-10%%)
Echo(
Pause
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q46747991.txt"
REM ************************ HIGH SCORES TABLE
REM **********************************************
:highscorestable
set /a count = 0
SET "manyspaces= "
for /f "tokens=1,2,3 delims=-" %%i in (%filename1%) do (
set hs=%%k&CALL :align hs -8
set hsn=%%i&CALL :align hsn 15
set hsv=%%j&CALL :align hsv 10
ECHO !hsn!!hsv!!hs!
set /a count+=1
if "!count!"=="5" goto end
)
:end
echo.
GOTO :EOF
:align
IF %2 gtr 0 (
CALL SET "%1=%%%1%%%manyspaces%"
CALL SET "%1=%%%1:~0,%2%%"
) ELSE (
CALL SET "%1=%manyspaces%%%%1%%"
CALL SET "%1=%%%1:~%2%%"
)
GOTO :eof
I edited your results for a source file which I named to suit my system, hence the sequence of coulmns is different from your unpublished source. I changed the metavariable-assignment to suit.
The :align routine peels potatoes by recognising the second argument as the required column-width, positive for left-align and negative for right-align.
The variable manyspaces is set to an obvious value, of sufficient length to cope with the widest column required. Obviously, since it won't change once established, it's best set in the very beginning of the batch.
The routine uses the call set %%var%% method so that it will work regardless of whether delayedexpansion is invoked or not.
The mechanics are, for instance
CALL SET "%1=%%%1%%%manyspaces%"
with %1=fred
First, parse the command. %1 is replaced by fred and %% by %, yielding
set
"fred=
%fred%[spaces]"
So appends the space-string to the current value of the environment variable specified as %1
The second set - analyse similarly; result is assigned to the environment variable specified as %1
So the routine can be used to generate a fixed-width string, appropriately aligned using any ordinary variable, even if the variable has a value of nothing (ie. is undefined)

Reading from a csv file and extracting certain data columns based on first column value

This is my first batch program and I have been searching online but still struggling to write up a solution.
I have the following CSV file:
"RH",2013/06/15 02:14:58 -0400,"X","LQ3SUEEWPWKL6",005,
"FH",01
"SH",2013/06/14 00:00:00 -0400,2013/06/14 23:59:59 -0400,"LQ3SUEEWPWKL6",""
"CH","TransactionID","InvoiceID",
......
I'm trying to write a simple program to do the following:
If column1 = "RH", then extract column2 value (2013/06/15 02:14:58 -0400)
If column1 = "SH", then extract column4 value (LQ3SUEEWPWKL6)
and pipe output to a file.
This is my code so far but the if condition is not working for me
#echo off
:: Set input file in variable
::Set _InputFile=%1
:: Store input line into different variables
FOR /F "tokens=1-18* delims=," %%A IN (%_InputFile%) DO (
Set _var1=%%A
Set _var2=%%B
Set _var3=%%C
Set _var4=%%D
Set _var5=%%E
Set _var6=%%F
Set _var7=%%G
Set _var8=%%H
Set _var9=%%I
Set _var10=%%J
Set _var11=%%K
Set _var12=%%L
Set _var13=%%M
Set _var14=%%N
Set _var15=%%O
Set _var16=%%P
Set _var17=%%Q
Set _var18=%%R
IF "%_var1%"=="RH" echo %var2%
)
My CSV file looks fine in Excel and Notepad but when I execute the script to display the first variable, it looks like there's some garbage characters just before the "RH" on the first record - I cannot bypass it since I need to extract additional column data if var1 = "RH":
"RH"
FH
01
SH
CH
TransactionID,PaymentTrackingID,
SF
SF
SC
RF
CAD,CR,0
RF
USD,CR,0
RC
FF
(
FOR /F "tokens=1-18* delims=," %%A IN (%_InputFile%) DO (
if "%%~A"=="RH" echo %%~B
if "%%~A"=="SH" echo %%~D
)
)>youroutputfilename
Should work - no need to assign all the values to different variables - BUT if you plan to use them, then
FOR /F "tokens=1-18* delims=," %%A IN (%_InputFile%) DO (
...
Set _var17=%%Q
Set _var18=%%R
CALL :PROCESS
)
...
GOTO :EOF
:PROCESS
IF %_var1%=="RH" echo %_var2%
IF %_var1%=="SH" echo %_var4%
GOTO :EOF
Note that with this method, since you are assigning %%x to _varx then if %%x is quoted, the quotes will be INCLUDED in the value assigned. To remove the enclosing quotes (if they exist) use SET _varx=%%~x.
Addendum 20130703-1956Z for OP's problem
#ECHO OFF
SETLOCAL
SET _Inputfile=u:\noname1.txt
(
FOR /F "tokens=1-18* delims=," %%A IN (%_InputFile%) DO (
SET "RH="
SET "SH="
ECHO(%%A|FINDSTR /l /c:"\"RH\"" >NUL
IF NOT ERRORLEVEL 1 SET RH=Y
ECHO(%%A|FINDSTR /l /c:"\"SH\"" >NUL
IF NOT ERRORLEVEL 1 SET SH=Y
if DEFINED RH echo %%~B
if DEFINED SH echo %%~D
)
)>u:\youroutputfilename
TYPE u:\youroutputfilename
del u:\youroutputfilename
echo========First way
(
FOR /F "tokens=1-18* delims=," %%A IN (%_InputFile%) DO (
SET _var1=%%A
SET "RH="
SET "SH="
CALL :process
if DEFINED RH echo %%~B
if DEFINED SH echo %%~D
)
)>u:\youroutputfilename
TYPE u:\youroutputfilename
del u:\youroutputfilename
echo========Second way
SETLOCAL ENABLEDELAYEDEXPANSION
(
FOR /F "tokens=1-18* delims=," %%A IN (%_InputFile%) DO (
SET _var1=%%A
IF "!_var1:~-4!"==""RH"" echo %%~B
IF "!_var1:~-4!"==""SH"" echo %%~D
)
)>u:\youroutputfilename
TYPE u:\youroutputfilename
del u:\youroutputfilename
echo========Third way
ENDLOCAL
GOTO :EOF
:process
IF "%_var1:~-4%"==""RH"" SET RH=Y
IF "%_var1:~-4%"==""SH"" SET SH=Y
GOTO :EOF
You have a parsing issue. First end the for loop with ), after this you can use the new variables:
#echo off
:: Set input file in variable
::Set _InputFile=%1
:: Store input line into different variables
FOR /F "tokens=1-18* delims=," %%A IN (%_InputFile%) DO (
Set "_var1=%%A"
Set "_var2=%%B"
Set "_var3=%%C"
Set "_var4=%%D"
Set "_var5=%%E"
Set "_var6=%%F"
Set "_var7=%%G"
Set "_var8=%%H"
Set "_var9=%%I"
Set "_var10=%%J"
Set "_var11=%%K"
Set "_var12=%%L"
Set "_var13=%%M"
Set "_var14=%%N"
Set "_var15=%%O"
Set "_var16=%%P"
Set "_var17=%%Q"
Set "_var18=%%R"
)
IF "%_var1%"=="RH" echo %var2%
You need to enable delayed expansion:
#echo off
setlocal EnableDelayedExpansion
set "_InputFile=..."
for /f "tokens=1-18* delims=," %%A in (%_InputFile%) do (
Set _var1=%%A
Set _var2=%%B
...
if "!_var1!"=="RH" echo !_var2!
)
as there was no answer to the "why does my line starts with "RH"", I'll do some gravedigging.
So, the  comes from the BOM (Byte Order Mark) which indicates the file is in UTF, and the way the bytes are written if necessary.
for the answer:
you can use
if x%_var1:RH=%x NEQ x%_var1%x (echo %_var2%)
this will check if RH is in %_var1% (if after replacing RH in the var, it is unchanged, RH is not in the var)
which means, whether the Bom is here or not is not important. Though, you'll have problems if you want an exact match.
another way to deal with it is to not include the bom in your file, which means saving either in ASCII or UTF-8 without BOM; Or using a tool to strip the bom from your UTF-8 file.

windows batch file array extraction counter not being incremented by +=

I am translating a shell script to windows batch. What I need to do is take all except 1,2 and last from command line arguments. join them and send to another program as argv.
#echo off
SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
ECHO %%A
set /a i+=1
IF %i% geq 2 (
set /a c+=1;
set candidates[!c!]=%%A
)
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%
I want the candidates array be argv[3..n-1]
e.g. If I write batch x 2 a b p it should pass a b to that another program
The problem is loop counter is not being incremented by += operator. If I write echo %1% inside FOR I see 0 always
You should not use for %%A in (%*) as it treats %* as filename set. This may cause problems, especially if you can pass * or ? (wildcard match characters in cmd) in parameters - as they will be expanded to all files satisfying pattern. Second, batch does really know nothing about arrays - a[1] and a[2] are just a shorthand notation for humans - they are two distinct variables.
Given the problem Parse command line, take second parameter as count of parameters to concatenate into a variable, here is my take:
#echo off
setlocal
set subject=%1
shift
set exp_count=%1
if not defined exp_count (
echo Count not specified
exit /b 1
)
set /a "verify=%exp_count%"
if %verify% leq 0 (
echo Count not valid /not a positive integer/
exit /b 2
)
set real_count=0
:loop
shift
if "%~1"=="" goto end_params
set /a real_count+=1
if %real_count% leq %exp_count% set "candidates=%candidates%%~1"
goto loop
)
:end_params
if %real_count% lss %exp_count% (
echo Less parameters passed than specified!
exit /b 3
)
echo %subject%
echo %candidates%
Please note I'm not checking if there is a 'hanging' parameter (the last, not being concatenated) but it should be trivial to add that check. I left it out on purpose to make the code more flexible.
I have two answers for your question:
1- The first problem is that in IF %i% ... command the value of i variable not change (although set /a i+=1 command will correctly increment the variable) and the way to solve it is by including setlocal EnableDelayedExpansion command at beginning and enclose i in percents signs this way: IF !i! ... (as said in previous answers). However, you must note that an array variable in Batch is different than a simple variable with same name (they both can exist at same time), so array elements must always be written with subscripts and there is NO way to process an entire array in a single operation. See this topic for further details.
In your program you must transfer the elements of candidates array into a simple variable, that in the example below have the same name (just to state my point):
#echo off
setlocal EnableDelayedExpansion
SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
ECHO %%A
set /a i+=1
IF !i! geq 2 (
set /a c+=1
set candidates[!c!]=%%A
)
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
REM Transfer "candidates" array elements into "candidates" simple variable:
set candidates=
FOR /L %%i IN (1,1,%c%) do (
set candidates=!candidates! !candidates[%%i]!
)
REM Show "candidates" simple variable:
echo %candidates%
Note that in Batch files you may insert commas, semicolons and equal-signs as separators instead spaces in most commands. However, SET /A command have other rules at this respect, so the semicolon must be omitted.
2- Independently of the array management explained above, this is the way I would solve your problem using a list instead of an array:
#echo off
SET subject=%1
shift
set count=%1
set candidates=
set lastArg=
set i=0
:nextArg
shift
if "%1" equ "" goto endArgv
set /a i+=1
set candidates=!candidates! !lastArg!
set lastArg=%1
goto nextArg
:endArgv
SET /a count_actual=i-3, count_expected=count
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%
Antonio
Yes your code will not increment i. Batch variable replacement occurs when a block is parsed, not when it is executed. The entire for block is parsed once, so %i% is replaced with zero before the for block is executed.
To disable that you need to enable delayed expansion and change your variable escape characters from %'s to !'s to have the replacement made at runtime. Then you will see i incremented in the for loop.
#echo off
Setlocal EnableDelayedExpansion
SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
ECHO %%A
set /a i+=1
IF !i! geq 2 (
set /a c+=1
set candidates[!c!]=%%A
)
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%
You will also need to get rid of the ; at the end of the set /a c+=1; line and I'm not sure what you are trying to do on line set candidates[!c!]=%%A as the brackets don't mean anything in batch.
While there are a bunch of answers already listed, I decided to add one more. My approach is to keep the answer as simple as possible for your specific needs. If you have any questions feel free to ask.
This will create the array as you desired [3,...,n-1] without the need for delayed expansion or fancy logic.
#echo off
:: Get the First Two Parameters
set "subject=%1"
shift
set "count=%1"
shift
:: Loop through the rest
set "index=0"
:NextParam
set "param=%1"
shift
set "next=%1"
:: Skip the last parameter
if not defined next goto EndParam
set "candidates[%index%]=%param%"
set /a "index+=1"
goto NextParam
:EndParam
set "count_actual=%index%"
set "count_expected=%count%"
:: Show the Results
echo %count_actual%
echo %count_expected%
echo %subject%
set candidates
Here is an alternate where the candidates are stored in a space delimited string instead of seperate variables. Replace the space between the %candidates% %param% to whatever delimiter you desire.
#echo off
:: Get the First Two Parameters
set "subject=%1"
shift
set "count=%1"
shift
:: Loop through the rest
set "index=0"
:NextParam
set "param=%1"
shift
set "next=%1"
:: Skip the last parameter
if not defined next goto EndParam
set "candidates=%candidates% %param%"
set /a "index+=1"
goto NextParam
:EndParam
set "count_actual=%index%"
set "count_expected=%count%"
:: Show Results
echo %count_actual%
echo %count_expected%
echo %subject%
echo %candidates%

Resources