Batch files: using the result of compare in variable? - if-statement

Here is the example:
set /a "number1=1"
set /a "number2=10"
if %number1% LSS %number2% (set /a "number1=%number1%+1")
echo result=%number1%
This code displays:
result=2
Is it possible in batch file to change the if statement to something like:
set /a "number1=%number1%+(%number1% LSS %number2%)"
?
The changed code at this moment displays:
Unbalanced parenthesis.
result=1

The set /A command does not feature comparison operators.
However, there is a way to compare two numbers and to get a value of -1 if the first number is less than the second one. For this, we need to know that the logical right-shift operator >> actually performs an arithmetic shift, meaning that the value of the most significant bit, which represents the sign, is shifted in at the left, hence the current sign of the number is maintained.
So for example:
the number +10 (binary representation 00000000 00000000 00000000 00001010) shifted to the right by one bit becomes +5 (binary representation 00000000 00000000 00000000 00000101);
the number -10 (binary representation 11111111 11111111 11111111 11110110) shifted to the right by one bit becomes -5 (binary representation 11111111 11111111 11111111 11111011);
When we shift to the right by 31 (or more) bit positions, the result is 32 times the sign bit (as we have 32-bit signed integers), which results in a value of -1 for negative input values and 0 for others.
When we now apply this technique, it leads us to the following code:
set /A "number1=%number1%-((%number1%-%number2%)>>31)"
You may omit the surrounding %-signs since set /A interprets any character strings that do not represent numbers or operators as variable names anyway:
set /A "number1=number1-((number1-number2)>>31)"
This can be further simplified using the appropriate assignment operator:
set /A "number1-=(number1-number2)>>31"

So your looking for something like a function or macro you can pass the values to for assessment?
The below is a macro demonstrating the concept. It is not a complete solution, as strings should be padded so they of equal length prior to assesment
#Echo Off
Set "Compare=Set "$RV="&For %%n in (1 2)Do if %%n==2 (For /F "Tokens=1,2 Delims={}" %%G in ("!Strings!")Do ((If "%%~G" LSS "%%~H" (Set "$RV=LSS") Else If "%%~G" EQU "%%~H" (Set "$RV=EQU") Else If "%%~G" GTR "%%~H" (Set "$RV=GTR"))&Echo/%%~G !$RV! %%~H))Else Set Strings="
Setlocal EnableDelayedExpansion
rem // example usage
%Compare:$RV=Ex[1]%{one}{oneb}
%Compare:$RV=Ex[2]%{one}{one}
%Compare:$RV=Ex[3]%{oneb}{one}
%Compare:$RV=Ex[4]%{13}{02}
%Compare:$RV=Ex[5]%{02}{13}
Echo/rem // Integers need to be 0 prefixed and strings should be padded to equal length or will return false:
%Compare:$RV=Ex[6]%{2}{13}
%Compare:$RV=Ex[7]%{two}{oneplus}
Set Ex[
Below is the fully realised compare macro that Pads strings to prevent false results when string lengths differ. The macro is defined using the \n newline syntax for the sake of readablitiy, however the compound version is also included.
#Echo Off & Setlocal DISABLEdelayedexpansion
rem // Pads string with 125 characters to prevent false results when string lengths differ. If comparing strings exceeding 125 characters in length,
rem // increase length of the padding and adjust s1 and s2 Substring modification length to match the number of padding characters.
Set "PAD=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
(Set \n=^^^
%= Newline Variable. Do not Modify. =%
)
Set Compare=Set "$RV=" ^& For %%n in (1 2)Do if %%n==2 (%\n%
For /F "Tokens=1,2 Delims={}" %%G in ("!Strings!")Do (%\n%
Set "s1=!PAD!%%~G" ^& Set "s1=!s1:~-125!" ^& Set "s2=!PAD!%%~H" ^& Set "s2=!s2:~-125!"%\n%
If "!s1!" LSS "!s2!" (Set "$RV=LSS")%\n%
If "!s1!" EQU "!s2!" (Set "$RV=EQU")%\n%
If "!s1!" GTR "!s2!" (Set "$RV=GTR")%\n%
Echo/%%~G !$RV! %%~H%\n%
)%\n%
)Else Set Strings=
Setlocal ENABLEdelayedexpansion
rem // example usages
For %%A in (one two three)Do for %%B in (three two one)Do %Compare:$RV=Ex[0]%{%%A}{%%B}
%Compare:$RV=Ex[1]%{one}{oneb}
%Compare:$RV=Ex[2]%{one}{one}
%Compare:$RV=Ex[3]%{oneb}{one}
%Compare:$RV=Ex[4]%{13}{2}
%Compare:$RV=Ex[5]%{2}{13}
Set Ex[
Endlocal & Endlocal & Goto :Eof
rem // compound version of Compare Macro:
Set "Compare=Set "$RV="&For %%n in (1 2)Do if %%n==2 (For /F "Tokens=1,2 Delims={}" %%G in ("!Strings!")Do (Set "s1=!PAD!%%~G"&Set "s2=!PAD!%%~H"&Set "s1=!s1:~-125!"&Set "s2=!s2:~-125!"&(If "!s1!" LSS "!s2!" (Set "$RV=LSS") Else If "!s1!" EQU "!s2!" (Set "$RV=EQU") Else If "!s1!" GTR "!s2!" (Set "$RV=GTR"))&Echo/%%~G !$RV! %%~H&Set "s1="&Set "s2=")) Else Set Strings="
Compare macro is case sensitive. Change the If conditions within the macro to include the /I switch if you require case to be ignored
To use the macro in the Desired context:
(%compare%{String 1}{String 2}) > Nul & If "!$RV!"=="LSS" (Echo/true)& Rem // replace Echo command within Parantheses with desired command
with Strings 1 and 2 being stand ins for whatever variables or For loop tokens you're comparing.

Related

Ridiculous caret escape sequence when mixing FOR and FINDSTR

I've got a string verification batch that handles rudimentary regex with FINDSTR and almost called it quits today when I thought I was unable to properly escape the caret character until I added a over a dozen ^.
Fail-verification Command: stringVerifier.bat "Derpy QFail" "^^^^^^^^^^^^^^^^QFail" /R
Pass-verification Command: stringVerifier.bat "QFail Derpy" "^^^^^^^^^^^^^^^^QFail" /R
stringVerifier.bat
#echo off
REM ===== Verify Sub-String In String Script =====
REM It uses Window's native findstr.exe commandline application with simplified options and scope for checking strings instead of file strings.
REM Call this script by preceeding the commandline call with the word `call` instead of directly running it.
REM
REM Parameter 1 is the string to search through. This must be wrapped in double-quotes.
REM Parameter 2 is the search pattern, e.g., "^QWARN". This must be wrapped in double-quotes.
REM Parameter 3 should be either /R for Regular Expression search or /L for a string-literal search.
REM Parameter 4 is optional. It should be true/false or t/f for case-sensitive searches.
REM Parameter 4 behavior will default to false for case-sensitivity if left out of the commandline parameters when called.
REM
REM You can check success by exit code or if the value of %match_was_found% is true/false or if %match_found% isn't empty.
REM A false value for %match_was_found% means there's no result to check due to no match occurring.
REM A non-empty value for %match_found% always indicates success, and vice-versa.
REM These values reset every time you run this script.
REM Extract between 1 from the front and 1 from the end to strip commandline quotes
Set string_to_search=%1
Set string_to_search=%string_to_search:~1,-1%
Set search_pattern=%2
Set search_pattern=%search_pattern:~1,-1%
Set search_type=%3
Set case_sensitive=%4
IF /i "%case_sensitive%"=="t" Set case_sensitive=true
IF /i "%case_sensitive%"=="f" Set case_sensitive=false
IF /i "%case_sensitive%"=="" Set case_sensitive=false
IF "%string_to_search%"=="" echo You forgot to provide parameter one, %string_to_search%, to specify your string to search, e.g., "Start of line of this string"&&exit /b 1
IF "%search_pattern%"=="" echo You forgot to provide parameter two, %search_pattern%, to specify your search pattern, e.g., "^Start of.*string$"&&exit /b 1
IF "%search_type%"=="" echo You forgot to provide parameter three, %search_type%, to specify your search type, e.g., /R or /L&&exit /b 1
IF /i NOT "%search_type%"=="/R" IF NOT "%search_type%"=="/L" echo You didn't provide the correct third parameter, %search_type%, for /R or /L&&exit /b 1
IF /i NOT "%case_sensitive%"=="" IF NOT "%case_sensitive%"=="true" IF NOT "%case_sensitive%"=="false" echo You didn't provide the correct fourth, %case_sensitive%, parameter for true or false&&exit /b 1
Set match_was_found=
Set match_found=
Set Command_To_Run=
Set Command_Ender=
Set Command_To_Run=echo.%string_to_search%
IF NOT "%case_sensitive%"=="" IF NOT "%case_sensitive%"=="true" Set Command_Ender=/I
IF "%search_type%"=="/R" (Set Command_Ender=%Command_Ender% /R %search_pattern%) ELSE (Set Command_Ender=%Command_Ender% /C:%search_pattern%)
FOR /F "tokens=*" %%i IN (' %Command_To_Run% ^| findstr.exe %Command_Ender% ') DO Set match_found=%%i
REM Deleting all variables we don't want retained as temporary env vars.
IF "%match_found%"=="" Set match_was_found=false&&Set string_to_search=&&Set search_pattern=&&Set search_type=&&Set Command_To_Run=&&Set Command_Ender=&&Set case_sensitive=&&exit /b 1
IF NOT "%match_found%"=="" Set match_was_found=true&&Set string_to_search=&&Set search_pattern=&&Set search_type=&&Set Command_To_Run=&&Set Command_Ender=&&Set case_sensitive=
REM Comment out this line or add more script logic if you want to disable console output of the matching line
echo %match_found%
exit /b 0
Is there any way to circumvent this ridiculous escape sequence in the batch itself without generated temp files and other such annoyances for escaping regex metacharacters?
You used set variable syntax is adverse.
As without quotes the carets will be used in any SET command to escape the next character.
This line will consume half of your carets
Set search_pattern=%search_pattern:~1,-1%
You should use the extended set syntax:
set "variable=content"
But you need only to change some of your lines to reduce the total amount of carets to two.
Set "search_pattern=%~2" This takes the argument and removes also the quotes
...
IF "%search_type%"=="/R" (Set "Command_Ender=%Command_Ender% /R %search_pattern%") ELSE (Set "Command_Ender=%Command_Ender% /C:%search_pattern%")
...
FOR /F "tokens=*" %%i IN (' %Command_To_Run% ^| findstr.exe %%Command_Ender%% ') DO Set match_found=%%i
Now you only need to use
stringVerifier.bat "QFail Derpy" "^^QFail" /R
That's because the last findstr still consumes one time the carets.
This could be changed also with quotes, but then you have to change your Command_Ender variable to hold only the options, but not the search string anymore.
To inspect the code you should use at some points a set Command_Ender or set search_pattern to show the real content of your variables.
You should also have a look at delayed expansion, as delayed expansion never changes the variable content.

regular expressions batch

I'm writing a calculator on a cmd with enabled binary operations. I need to validate input data (remove letters, and other symbols that are not required for arithmetic operations)
#echo off
set data=
echo %* | findstr /R "\/\? ECHO" > nul
IF "%ERRORLEVEL%" EQU "0" goto printHelp
:main
set data= %data%%1
shift
if "%1" == "" (
echo %data% | findstr /R "^[0123456789*-+()/%!^_&|]*$" >nul 2>&1
if "%ERRORLEVEL%" EQU 0 (
echo Incorrect input data
exit /B
)
goto :result
) else (
goto :main
)
:result
set /a data="%data%"
echo %data%
exit /B
:printHelp
echo.
echo --------------------------------------------------
echo Using: calculator.bat [/?] [EXPRESSION]
echo helps you to consider arithmetic in Command Line
echo --------------------------------------------------
exit /B
My regular expression is not working. Also not considered to be a binary operation. What could be the problem?
Part 1 - Why your "regex is not working"
Your logic is wrong. FINDSTR sets ERRORLEVEL to 0 if there is a match, 1 if no match. Your regex is verifying that all characters are "valid", but your condition is treating a match as incorrect input.
Your IF statement uses quotes on one side, but not on the other. You must be consistent, otherwise it can never evaluate to TRUE.
Percent literals must be doubled within a batch script. Your regex has a percent literal that should be written as %%.
You use %ERRORLEVEL% in the same code block that sets the value. This cannot work because the value is expanded when the code block is parsed - before the value is set.
The simplest alternative is to use if errorlevel 1, which returns true if ERRORLEVEL is >= 1.
Another option is to enable delayed expansion with SETLOCAL ENABLEDELAYEDEXPANSION at top, and then use if !errorlevel! neq 0. But this would require that quoted ! literal in your regex be escaped as ^!, and ^ literal escaped as ^^.
My favorite option is to use the && and || conditional operators instead of IF.
findstr ... >nul && (match found statements) || (no match statements)
In your case, you want to take action if there was no match, so you only need the || operator.
Part 2 - Why your whole concept is not a good idea
Your validation is overly simplistic. Simply screening out invalid characters does not prevent errors. For example, 1**2 will result in an error, even though all characters are "valid". There are many other inputs with "valid" characters that would result in an error.
SET /A can work directly with environment variables. It knows how to access the value without you expanding the value in your code. This can be a powerful tool. A variable name used in a computation can include any character that is not an operator. So one can argue that there are no invalid characters for SET /A computations. Your exclusion of "invalid" characters prevents use of variables in computations.
Below is a simple batch calculator program I wrote some time ago. It is in an endless loop requesting input and displaying the result, until you enter a quit command. It supports all operators supported by SET /A.
It allows you to define and use variables in your expressions. The result of the most recent computation is always stored in a variable named #.
The calculator can display results as decimal, hexidecimal, or binary.
By default, it only displays the result of the last computation. It can be instructed to also display the value of all variables after each computation.
You can enter a command instead of a math computation. All commands begin with a \
\ Quit
\V Toggle variable listing ON or OFF
\D Decimal mode - results are displayed as decimal
\H Hex mode - results are displayed as hexidecimal
\B Binary mode - results are displayed as binary
\C X Clear variable X
\C * Clear all variables
\C X* Clear all variables that begin with X
Entering nothing will list all the currently defined variables.
Cleared variables are undefined. Note that an undefined variable has an implicit value of 0.
Here is the code:
#echo off
setlocal enableDelayedExpansion
for /f "delims==" %%v in ('set') do set %%v=
set __skip=#COMSPEC#PATHEXT#PROMPT#__mode#__str#__skip#__clr###__dispVars#
set __mode=Dec
set __dispVars=0
:top
echo:
set __str=
set /p "__str=%__mode%> "
if "!__str!"=="\" exit /b
if "!__str!"=="" call :dispVar # & call :dispVars & goto :top
if /i "!__str:~0,2!"=="\C" call :clearVars &goto :top
if /i "!__str!"=="\H" (set __mode=Hex) ^
else if /i "!__str!"=="\D" (set __mode=Dec) ^
else if /i "!__str!"=="\B" (set __mode=Bin) ^
else if /i "!__str!"=="\V" (set /a "__dispVars=^!__dispVars") ^
else set /a #=(!__str!)
call :dispVar #
if !__dispVars! gtr 0 call :dispVars
goto :top
:clearVars
for /f "delims=,; " %%v in ("!__str:~2!") do (
set __clr=%%v
if "!__clr:~-1!"=="*" (
set __clr=!__clr:~0,-1!
for /f "delims==" %%x in ('set !__clr!') do (
if "!__skip:#%%x#=!"=="!__skip!" set "%%x="
)
) else set "%%v="
)
call :dispVar #
call :dispVars
exit /b
:dispVars
setlocal
for /f "tokens=1,2 delims==" %%v in ('set') do if "!__skip:#%%v#=!"=="!__skip!" call :dispVar %%v
exit /b
:dispVar Var
setlocal
if !__mode!==Hex call :num2hex %1 disp
if !__mode!==Bin call :num2bin %1 disp
if !__mode!==Dec set /a disp=!%~1!
set var=%~1
if "!var:~0,6!"=="!var!" (
set "var=!var! ----------"
set "var=!var:~0,6!"
)
echo %var% = !disp!
exit /b
:num2hex NumVal RtnVar
setlocal enabledelayedexpansion
set hex=
set /a "dec=%~1"
set "map=0123456789ABCDEF"
for /l %%n in (1,1,8) do (
set /a "d=dec&15,dec>>=4"
for %%d in (!d!) do set "hex=!map:~%%d,1!!hex!"
)
(endlocal & rem return values
set %~2=%hex%
exit /b
)
exit /b
:num2bin NumVal RtnVar
setlocal enabledelayedexpansion
set bin=
set /a "dec=%~1"
for /l %%n in (1,1,32) do (
set /a "d=dec&1,dec>>=1"
set "bin=!d!!bin!"
)
(endlocal & rem return values
set %~2=%bin%
exit /b
)
exit /b
And here are the results of a short session:
D:\test>calculate.bat
Dec> 2*3
# ---- = 6
Dec> a=#+1
# ---- = 7
Dec>
# ---- = 7
a ---- = 7
Dec> b=(a+=5)*2
# ---- = 24
Dec> \v
# ---- = 24
a ---- = 12
b ---- = 24
Dec> c=b/3
# ---- = 8
a ---- = 12
b ---- = 24
c ---- = 8
Dec> \h
# ---- = 00000008
a ---- = 0000000C
b ---- = 00000018
c ---- = 00000008
Hex> \b
# ---- = 00000000000000000000000000001000
a ---- = 00000000000000000000000000001100
b ---- = 00000000000000000000000000011000
c ---- = 00000000000000000000000000001000
Bin> \
D:\test>

Linefeed in batch regex

I want to match all lines of the following text with FINDSTR /R
LABO_A =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))
(CONNECT_DATA =
(SERVICE_NAME = LABO)
)
)
I already tried What are the undocumented features and limitations of the Windows FINDSTR command?
Especially the "Searching across line breaks" part. But unfortunately it didn't work.
My approach is the following:
SETLOCAL
set LF=^
FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"
SETLOCAL enableDelayedExpansion
FINDSTR /R "LABO_A.=.!CR!*!LF!.*(DESCRIPTION.=.!CR!*!LF!.*(ADDRESS.=.(PROTOCOL.=.TCP)(HOST.=.host01)(PORT.=.1521))!CR!*!LF!.*(CONNECT_DATA.=!CR!*!LF!.*(SERVICE_NAME.=.LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH%
Am I missing something? Or is the batch regex simply not powerful enough to realize this?
SOLUTION:
The approach of #dbenham let me reconsider my regex-string. So I edited it to
FINDSTR /R /C:"LABO_A =!CR!*!LF!.*(DESCRIPTION =!CR!*!LF!.*(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF!.*(CONNECT_DATA =!CR!*!LF!.*(SERVICE_NAME = LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH% > NUL
I removed some unnecessary white spaces and adapted the parameters of FINDSTR.
Now it works.
Your regex is wrong. Your source lines end immediately after the =, but the extra . in your regex is looking for an additional character after the =.
It looks to me you are using . to represent white space. I think you would be better off using actual spaces, but then you need the /C option.
The following matches the lines successfully.
#echo off
SETLOCAL
set LF=^
FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"
SETLOCAL enableDelayedExpansion
FINDSTR /R /C:"LABO_A =!CR!*!LF! *(DESCRIPTION =!CR!*!LF! *(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF! *(CONNECT_DATA =!CR!*!LF! *(SERVICE_NAME = LABO)!CR!*!LF! *)!CR!*!LF! *)" test.txt
Note that even though all lines in the regex are matched, only the first line of the matching set is printed.
I suspect that the line breaks are not required in your configuration file. Here is another variation that allows for more variation in the white space.
#echo off
setlocal enableDelayedExpansion
set LF=^
FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"
set "ws=[ !cr!!lf!]*"
FINDSTR /RX /C:"LABO_A =!ws!(DESCRIPTION =!ws!(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!ws!(CONNECT_DATA =!ws!(SERVICE_NAME = LABO)!ws!)!ws!)!ws!" test.txt
I also attempted to allow white space in every place I thought possible, but that exceeded FINDSTR's maximum REGEX string length.
Essentially, batch regex isn't powerful enough. SED would be better no doubt.
Nonetheless, here's a way to detect that a sequence of lines appears in a file. It's a little restricted, but should suffice for the sequence you've nominated. It assumes that leading spaces are not significant.
#ECHO OFF
SETLOCAL enabledelayedexpansion
FOR /f "delims==" %%a IN ('set l_ 2^>nul') DO "SET %%a="
SET /a lines=0
FOR /f "tokens=*" %%a IN (q19859936.txt) DO SET /a lines+=1&SET l_!lines!=%%a
SET hits=0
SET "stop="
FOR /f "tokens=*" %%a IN (q19859936.test) DO (
SET l_0=%%~a
CALL :test
IF DEFINED stop GOTO done
)
:done
IF DEFINED stop (ECHO FOUND ) ELSE (ECHO NOT FOUND)
GOTO :EOF
:test
SET /a hits+=1
ECHO IF NOT "!l_%hits%!"=="%l_0%"
IF NOT "!l_%hits%!"=="%l_0%" SET hits=0&IF %hits%==1 (GOTO :eof) ELSE (GOTO test)
IF %hits%==%lines% SET stop=Y
GOTO :eof
[edited code 20131111T1408Z - first FOR had tokens=2]
The initial FOR ensures that variables L_* are cleared.
The file q19859936.txt is read as the line-sequence-to-be-detected data.
q19859936.test is then examined. Each line is assigned to L_0 in turn and the internal subroutine :test will check to see whether it matches the next-line-expected.
The IF NOT statement is significant - and seemingly illogical (you'd need to add the /i switch to make it case-insensitive if you so want...) When batch parses the line, %hits% is replaced by the then-current value of hits and THEN the line is executed, so hits will be reset to 0 if ever a mismatch is found. If the HITS count WAS not 1, then the test is repeated. This takes care of the case
matches line 1
matches line 2
matches line 3
matches line 1
matches line 2
matches line 3
matches line 4
matches line 5
matches line 6
where the second "line 1" is encountered when "line 4" was expected. HITS is thus changed to 0, but it WAS 4 so execution passes back to :test and the test repeated with HITS=1.
Another approach could have been to read lines into another array (say L#*) and test that L_* matched L#*, for %LINES% entries. On no match, ripple-up and assign the next line read to L#!lines! ... but I thought of that later. Probably be easier and better, too - I'll leave it as an exercise for whoever may be interested.
This will work if you are after the LABO_A reference.
It uses a helper batch file called findrepl.bat from - https://www.dropbox.com/s/rfdldmcb6vwi9xc/findrepl.bat
Place findrepl.bat in the same folder as the batch file or on the path.
type "file.txt" | findrepl "^LABO_A =" /e:"^ \)"

Syntax for specific RegEx in command line FINDSTR call

I am writing a batch script that takes in various arguments before starting another process. In the example below I am checking the case where the first argument was 1, and the second argument is in the form of "any number of digits 0-9, followed by the letter k, m, or g" (I am specifying the amount of memory the process should start with i.e. 10g = 10 Gb memory).
If I just want a number this will suffice:
IF [%1] EQU [1] ECHO %2|findstr /r "[^0-9]" > nul
IF [%1] EQU [1] IF errorlevel 1 echo starting test number %1 with %2 of memory
What I thought would be an obvious segway to add the letters k, m, or g led me to this (I've tried with and without the '*'):
IF [%1] EQU [1] ECHO %2|findstr /r "[^0-9]*[kmg]" > nul
IF [%1] EQU [1] IF errorlevel 1 echo starting test number %1 with %2 of memory
However I have been unable to match any string to this FINDSTR pattern. Basically I am looking for a FINDSTR that matches [0-9][0-9]*[kmg]. I am fairly certain I am close but am having trouble working out the correct syntax.
Even the first code you posted does not work. [^0-9] looks for any non-digit. I think you wanted ^[0-9], which means any string that starts with a digit. Your logic is also wrong: FINDSTR sets errorlevel to 0 if found, and 1 if not found. I prefer to use the conditional && and || operators to test the result instead of IF.
I recommend the following for what you are attempting. I've thrown in the /I switch to make it case insensitive. I add the /X switch to prevent the string from matching if there are extra characters before or after the number with suffix.
#echo off
if "%~1" equ "1" echo(%~2|findstr /rix "[0-9][0-9]*[kgm]" >nul && (
echo starting test number %~1 with %~2 of memory
)
Unfortunately, FINDSTR does not support the ? meta-character. So the solution is slightly more complicated if the suffix is optional (if you want to support bytes, kilobytes, megabytes, and gigabytes). You would need to search for either of 2 strings, one with the suffix, and one without. FINDSTR breaks the search string into multiple search strings at spaces.
#echo off
if "%~1" equ "1" echo(%~2|findstr /rix "[0-9][0-9]*[kgm] [0-9][0-9]*" >nul && (
echo starting test number %~1 with %~2 of memory
)

Batch File If statement inside For loop

I am having the issue where my if statement (inside a for loop), doesn't seem to cooperate. What I am trying to do is this:
Loop through a bunch of zip files and rename them 005.zip, 006.zip, 007.zip, etc.
I keep a counter, starting at 5, that determines the file number, and a prefix that is 00 in order to get 005, 006, and so on.
Once the counter reaches 10, I want the prefix to just be 0 instead of 00. So when the counter is ten, that file will be named 010.zip, and then 011.zip instead of 0010.zip, 0011.zip etc.
Here is what I have thus far:
setlocal enableextensions enabledelayedexpansion
SET /a COUNT=5
SET FILE_PREFIX=00
SET /a MAX=10
for %%f in (*.zip) do (
if !COUNT! == !MAX! (set FILE_PREFIX=0)
ren "%%f" %FILE_PREFIX%!COUNT!.zip
set /a COUNT+=1
echo !COUNT!
)
endlocal
Why doesn't the if statement work? The file renaming is working fine, it is just that if statement that doesn't change the FILE_PREFIX to 0.
The problem is that your code doesnt apply delayed expansion to the FILE_PREFIX so the value is calculated just once in the loop, at parse time; instead of being refreshed every iteration at runtime.
Just change your line to
ren "%%f" !FILE_PREFIX!!COUNT!.zip
and presto! it should work.
But once you correct it, still your method would fail for numbers above 999.
For a more robust implementation, try this alternative
SET /a count=1
for %%f in (*.zip) do (
set fn=0000!count!
echo REN "%%f" !fn:~-4!%%~xf
set /a count+=1
)
Inside the loop
the code 0000!count! appends some zeros (4 in this case) to the number; so it will follow the sequence 00001, 00002, ... 00009, 000010, 000011, ...
then !fn:~-4! removes all digits but the last N (4 in this example). So it will follow the desired sequence 0001, 0002, ... 0009, 0010, 0011, ...
and %%~xf extracts the extension (.zip in all the cases of this loop) and appends it to form the final filename. So it will follow the desired sequence 0001.zip, 0002.zip, ... 0009.zip, 0010.zip, 0011.zip, ...
This method will work for any number up to 9999. You can easily extend it to 5 o 6 or even more digits.