BATCH IF condition for specific format - windows

How to form IF condition to be true when 2nd argument are 3 numbers separeted with dot.
I tried this (which should be for any character, not just numbers) but not work.
IF /I "%2"=="*.*.*" SET VAR=%2
How can i do that?

#ECHO OFF
SETLOCAL
SET "leadnum=123456789"
SET "anynum=%leadnum%0"
FOR %%i IN (
1.2.3
123.456.789
012.345.678
12.3
12
12a.345.678
12.34.56.78
12.34.777f
12.34.
12.34.56.
) DO (
ECHO %%i|FINDSTR /b /e "[%leadnum%][%anynum%]*\.[%leadnum%][%anynum%]*\.[%leadnum%][%anynum%]*" >NUL
IF ERRORLEVEL 1 (ECHO %%i is NOT of format) ELSE (ECHO %%i is IN format)
)
GOTO :EOF
Here's a demo. You don't say what constitutes a number, so I arbitrarily made the decision to define a number to be a string which starts with a numeric character (except '0') and is followed by any number of numeric characters.

IF doesn't support placeholders, so you have to emulate them
echo %2||findstr /R "^[0-9]\.[0-9]\.[0-9]$" && (set "var=%2") || (echo no match)
^ start at the first position of the string
\. a dot. (. only would be "any char")
[0-9] any number (you can also use or example [1-9] if needed)
$ end of string.
&& if previous command (findstr) was successful then...
|| if previous command (findstr) failed then...

set "value=%2" & setlocal enabledelayedexpansion
for %%a in (1 2 3 4 5 6 7 8 9) do set "value=!value:%%a=0!"
endlocal & if "%value%"=="0.0.0" ( set "var=%2" ) else ( set "var=" )
echo(%var%
This just replaces all the numbers with a 0 and tests the valid ending value

Related

"ECHO" showing up in the middle of generating random characters for some reason?

So my code here:
#echo off
pause
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set alfanum=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
:a
timeout /t 1
set generator=
FOR /L %%b IN (0, 1, 5) DO (
SET /A rnd_num=!RANDOM! * 62 / 32768 + 1
for /F %%c in ('echo %%alfanum:~!rnd_num!^,1%%') do set generator=!generator!%%c
)
echo %generator%
goto generator
Is slightly broken because sometimes "ECHO" shows up in the middle of generating. for example:
vMECHO8ECHOE <<
DQTGv0
aECx5i
lLECHOO3H <<
cOd4ECHOg <<
6950pC
Help? running on Windows 10 CMD.
Substring modification is 0 indexed. ensure the index you use is EQU to the number of characters - 1
FOR /L %%n IN (0,1,5)Do For /F "delims=" %%c In ( 'SET /A "_r=!RANDOM! %% 62"' )Do (
Set "generator=!generator!!alfanum:~%%c,1!"
)
Remove the + 1 from your set /A command line and you will be fine:
set /A "rnd_num=!RANDOM!*62/32768"
Which can be simplified to:
set /A "rnd_num=!RANDOM!%%62"
You actually point past the string in !alfanum!, because the position index for sub-string expansion is zero-based, meaning 0 points to the first character, and 61 to the last one in your 62-character string. Your current code returns 62 as the greatest possible random number, so the sub-string expansion returns an empty string, which lets the echo command in your for /F loop output ECHO is {on|off}., resulting in the result ECHO due to the default token string tokens=1 of for /F.
Anyway, The for /F loop is not necessary, just replace it by the line:
rem /* The standard `for` loop ensures that the value of `!rnd_num!` is expanded
rem BEFORE delayed sub-string expansion of `!alfanum:~...!` occurs: */
for %%a in (!rnd_num!) do set "generator=!generator!!alfanum:~%%a,1!"
Or (slower):
rem /* The `call` command ensures that the sub-string of `%alfanum:~...%`
rem is expanded AFTER delayed expansion of `!rnd_num!` occurs: */
call set "generator=!generator!%%alfanum:~!rnd_num!,1%%"

How to request integer input from user in batch file

I want to create a batch file on Windows that can let the user enter only a number between 1-31... I could use this number later in the batch file... It is possible ?
I tried this
set /P "month=Enter the month of the year : "
findstr /i %month% %file% | sort /+24
Thanks :)
#echo off
:try_again
set /P "month=Enter the month of the year : "
echo %month%|findstr /r "[^0-9]" && (
echo enter a number
goto :try_again
)
::clears the leading zeroes.
cmd /c exit /b %month%
set /a month=%errorlevel%
if %month% gtr 31 (
echo enter a number between 1 and 31
goto :try_again
)
if %month% lss 1 (
echo enter a number between 1 and 31
goto :try_again
)
?
Well, these two options are entirely different:
Let the user enter anything; then, check if the input is a number between 1 and 12 and retry the input if it is not.
Let the user just enter a number between 1 and 12.
The Batch file below implement the second method:
#echo off
setlocal EnableDelayedExpansion
echo Precede numbers 1 and 2 by a zero
set /P "=Enter a month: " < NUL
choice /C 0123456789 > NUL
set /A "number=%errorlevel%-1"
if %number% gtr 1 echo %number% & goto continue
set /P "=%number%" < NUL
if %number% equ 0 (
choice /C 12 > NUL
set "digit2=!errorlevel!"
) else (
choice /C 012 > NUL
set /A "digit2=!errorlevel!-1"
)
echo %digit2%
set /A "number=number*10+digit2"
:continue
echo/
echo Number read: %number%
A very simple but efficient method I use when I need a non-zero numeric input is the following code (note that this verifies the user entry afterwards):
:RETRY_RESET
rem /* Since zero is considered as invalid, preset variable to `0` to
rem not keep the former value in case the user just presses ENTER;
rem you could also define a non-zero default value here optionally: */
set /A NUMBER=0
:RETRY_REUSE
rem // Display prompt now:
set /P NUMBER="Please enter a positive number: "
rem /* Convert entry to a numeric value; everything up to the first
rem numeral is converted to a numeric value, except leading SPACEs
rem or TABs are ignored and signs `+` and `-` are recognised: */
set /A NUMBER+=0
rem /* Caution: numbers with leading `0` are converted to octal ones!
rem since `8` and `9` are not valid octal numerals, entries with
rem such figures and leading zeros are converted to `0`! */
rem // Verify entry:
if %NUMBER% EQU 0 goto :RETRY_RESET
rem // Do something with `%NUMBER%` at this point...
rem /* Afterwards you can jump to `:RETRY_RESET` to enter another number;
rem alternatively, jump to `:RETRY_REUSE` to maintain the former entry
rem in case the user just presses ENTER... */
This will not fail for any entry you can think of because the variable NUMBER holding the value is never expanded before it is converted to a true number by set /A NUMBER+=0.
The script recognises + and - signs correctly. Leading white-spaces are ignored. Besides all those, everything up to the first non-numeric figure is converted to a number; so for instance, an entry like SPACE+15.75k is converted to 15 as the . is not a numeral.
The disadvantage of this approach is that leading zeros may lead to unexpected results as set /A interpretes numbers with such as octal ones; so for instance, 012 is converted to (decimal) 10, and 08 and 09 are converted to 0 as 8 and 9 are not valid octal digits.
A good point though could be the fact that hexadecimal numbers are recognised correctly in case they are prefixed with 0x; for example, 0x18 is converted to 24; 0xAS becomes 10 (as S is not hex.).
A safe and simple manner for performing this task is the use of the Set /A command in conjunction with the || conditional operator and a :label to return to for when invalid input is entered.
A number of tests can be performed on the input value using set /a without expanding the variables content in a manner that leaves your code vulnerable to code injection.
An example:
#Echo off
Call:ValidNum $RV 31
Call:ValidNum "" "" 5
Set $
Goto:Eof
:ValidNum [returnvar] [max] [min]
SETLOCAL
Set "sign=-1"
:VNumIn
%= ensure nul value =%
Set "input="
%= define max value =%
2> nul Set /a "max=%~2" || Set "max=2147483647"
%= define min value =%
2> nul Set /a "min=%~3" || Set "min=1"
Set /p "input=Enter a number GEQ %min% LEQ %max%: "
%= Input Testing. input +/- , input > min , input < max , Hex/Octal for comparison =%
2>nul Set /a "1/(sign-(input>>31))","max/(input/min)","1/(max/input)","HexOct=input" || Goto:VNumIn
%= compare assignments to block hex, octal and leading 0's =%
If not "%Input%"=="%HexOct%" Goto:VNumIn
( %= return value in $Num if no arg 1, else return in Arg1 =%
ENDLOCAL & Set "%~1=%input%" 2> nul || Set "$Num=%input%"
Goto:Eof
)
The following script is sort of a mixture of both restricting characters/key during entry and verifying characters/value after entry. The code is quite complex but it is very flexible and also safe. Here is it:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here (`findstr` reg. expr.):
set "WHITE=[0-9]" & rem // (positive list, accepted characters)
set "BLACK=[^`^]" & rem // (negative list, rejected characters)
set "LENGTH=2" & rem // (optional limit for length of entry)
rem // resolve length limit:
set /A LENGTH-=1
if %LENGTH% LSS 0 set "LENGTH="
rem // Retrieve back-space character:
for /F %%C in ('echo prompt $H ^| cmd') do set "BS=%%C"
:HOOK
rem // Display prompt:
echo(Please enter something:
set "ENTRY="
:LOOP
rem // Use `xcopy /W` to capture a single key stroke:
set "KEY="
for /F "delims=" %%K in ('2^> nul xcopy /L /W "%~f0" "%~f0"') do (
if not defined KEY set "KEY=%%K"
)
set "KEY=%KEY:~-1%"
rem // Leave loop in case ENTER has been pressed:
if not defined KEY goto :NEXT
rem // Disallow `"` to avoid syntax errors (`if`, no del. exp.):
set "KEY=%KEY:"=%" & rem "
rem // Disallow `=` to avoid syntax errors (`set /P`):
if "%KEY%"=="=" set "KEY="
rem // Disallow ` ` (tabulator):
if "%KEY%"==" " set "KEY="
rem // Optional additional filter (include):
if defined WHITE (
(echo("%KEY%" | > nul findstr /R /C:"%BS%" /C:"%WHITE%") || (
set "KEY="
)
)
rem // Optional additional filter (exclude):
if defined BLACK (
(echo("%KEY%" | > nul findstr /R /C:^"\"%BLACK%\"^") || (
set "KEY="
)
)
rem // In general, display string equals pressed key:
set "DISPLAY=%KEY%"
rem // Avoid space in display text (ignored by `set /P`):
if "%KEY%"==" " set "DISPLAY=_%BS% "
rem // Force to clear preceding character upon back-space:
if "%KEY%"=="%BS%" (
set "DISPLAY=%BS% %BS%"
if defined ENTRY set "ENTRY=%ENTRY:~,-1%"
set "KEY="
)
rem // Ignore any more character if length limit is reached:
set "TEST=%ENTRY%"
if defined LENGTH if defined ENTRY (
call set "TEST=%%ENTRY:~,%LENGTH%%%"
)
if not "%TEST%"=="%ENTRY%" (
set "KEY=" & set "DISPLAY="
)
set "ENTRY=%ENTRY%%KEY%"
rem // Show display text:
< nul set /P ="%DISPLAY%"
goto :LOOP
:NEXT
echo(
rem /* Verify the entry; for instance,
rem check numeric value after removal of leading zeros: */
cmd /C exit %ENTRY%
set /A ENTRY=%ErrorLevel%
set /A ENTRY+=0 & rem // (conversion to true numeric value)
if %ENTRY% LEQ 0 goto :HOOK
if %ENTRY% GTR 12 goto :HOOK
rem // Do something with the entry (display):
echo(You entered this value:
< nul set /P ="%ENTRY%"
echo(
endlocal
exit /B
The core of the script is the xcopy /L /W command which takes a single key stroke (/W) and does no copying (/L). Its output is captured by a for /F loop to get the current key or character. For displaying < nul set /P is used with nothing sent into its prompt but the message text displayed, which is not terminated by a line-break unlike echo. Consult also the comments (rem) in the code.
The script can be configured in the Define constants here block at the top:
variable WHITE defines a positive character set for the findstr command, one of which a character/key must equal; set to an empty string to disable this set; for our situation, [0-9] is suitable as it defines to accept only numeric figures;
variable BLACK defines a negative character set for the findstr command, one of which a character/key must not equal; set to an empty string to disable this list; since there is already WHITE defined, BLACK is not needed; the first character within the brackets [ ] must be a caret ^ so that the given characters are truly rejected; if the sets in WHITE and BLACK overlap, the latter takes precedence;
variable LENGTH defines the greatest length of the entry, so if the given number of characters have been supplied, no more are accepted; you can delete the last character though by the &leftarrow;— key; since we need a two-digit numeric value, 2 is the value of choice here;

Time comparision in batch file not working

Basically what I'm trying to create is a script that only will run if the time is LEQ than 19:00 (7 PM), what I did so far is:
set myTime=%time%
set myFlag=false
if %myTime% LEQ 19:00 set myFlag=true
if myFlag=true (
*my script*
)
It returns this error message: "86 was not expected at this moment", (86 being the last numbers of the variable 'myTime' [14:36:11,86]. It just won't work.
I've also tried:
set myTime=%time%
set myFlag=false
if %myTime% LEQ 19:00:00,00 set myFlag=true
if myFlag=true (
*my script*
)
Both ways i get the same error message double-digit number not expected. Any thoughts on how to solve this? It's even possible do a time comparision on a windows batch file?
Syntax: Escape Characters, Delimiters and Quotes
Delimiters
Delimiters separate one parameter from the next - they split the
command line up into words.
Parameters are most often separated by spaces, but any of the
following are also valid delimiters:
Comma (,)
Semicolon (;)
Equals (=)
Space ( )
Tab ( )
Notice that although / and - are commonly used to separate command
options, they are absent from the list above. This is because batch
file parameters are passed to CMD.exe which can accept it's own
parameters (which are invoked using / and - )
Next code snippet should work (see set /? and if /?):
set "myTime=%time%"
set "myFlag=false"
if "%myTime%" LEQ "19:00:00,00" set "myFlag=true"
if "%myFlag%"=="true" (
echo *my script*
)
Note that above code snippet is locale dependent. You can try next locale independent solution similar to this answer to another question:
SETLOCAL EnableExtensions
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "myTime=%%a"
set "myTime=%myTime:~8,6%"
set "myFlag=false"
if "%myTime%" LEQ "190000" set "myFlag=true"
if "%myFlag%"=="true" (
echo *my script*
)
Read
WMIC.exe: Windows Management Instrumentation Command
localdatetime: Win32_OperatingSystem class property in CIM_DATETIME format
set "myTime=%myTime:~8,6%": Extract part of a variable (substring)
Set Ag=WScript.Arguments
If CDate(Ag(0)) > CDate(Ag(1)) then
Wscript.echo "Param 1 greater than Param 2"
wscript.quit 0
else
Wscript.echo "Param 1 NOT greater than Param 2"
wscript.quit 1
End If
To use in batch (use any valid time/date string)
scriptname.vbs 7pm 8pm
If errorlevel 0 if not errorlevel 1 echo Param 1 greater than param 2
If errorlevel 1 if not errorlevel 2 echo Param 2 greater than param 1
Or
scriptname.vbs 19:00:00 20:00:00
If errorlevel 0 if not errorlevel 1 echo Param 1 greater than param 2
If errorlevel 1 if not errorlevel 2 echo Param 2 greater than param 1

How to find total commas in the first line of a file?

I want create a batch file to find the total number of commas in the first line of text file.
Sample Text File
input.txt
12345,Bhavik
12323,Bhavik,Sanghvi
Output
1
I tried to surf net for this but couldnt find a solution, please help
Here's another simple solution to this question.
#echo off
setlocal enabledelayedexpansion
set LF=^
::Above 2 blank lines are critical - do not remove
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
set /p var=<input.txt
echo "%var:,="!cr!!lf!"..***..%">temp.file
find /c "..***.." <temp.file
del temp.file
#echo off
setlocal EnableDelayedExpansion
rem Read the first line
set /P "line=" < input.txt
rem Store it in a text file
> before.txt echo !line!
rem Store the line without commas in a second file
> after.txt echo !line:,=!
rem Get the difference in sizes between both files
set "diff="
for %%a in (before.txt after.txt) do (
if not defined diff (
set "diff=%%~Za"
) else (
set /A "diff-=%%~Za"
)
)
del before.txt after.txt
echo %diff%
If, rather than being hampered by the awful Windows BATCH tools, you install awk from the Unix tools for Windows here, you can do this:
awk -F, 'NR==1{print NF-1;exit}' input.txt
That says... "Run awk and use commas as the separator to divide fields. On line 1, print the number of fields on this line minus 1, then exit. Do that for file input.txt."
gawk is just a slightly different version of awk if you get that one in the Unix Utils package. You may need to replace the single quotes with double ones to accommodate Windows' lack of abilities.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q35826440.txt"
:: first method
SET /a count=0
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO SET "line=%%a"&GOTO got1
:got1
SET "line=%line:"=%"
IF NOT DEFINED line ECHO method 1: %count% found&GOTO method2
IF "%line:~-1%"=="," SET /a count+=1
SET "line=%line:~0,-1%"
GOTO got1
:: second method
:method2
SET /a count=-1
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO SET "line=%%a"&GOTO got2
:got2
SET "line=%line:"=%"
SET "line=%line:;=%"
SET "line=%line: =%"
SET "line=%line:,=x,x%"
FOR %%a IN (%line%) DO SET /a count+=1
ECHO method 2: %count% found
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q35826440.txt containing your data for my testing.
Two methods - both read the first line to line, then removes any " characters.
The first then mechanically loops, checking whether the last character is a comma, counting if it is and removing the last character until the string found is empty.
The second replaces all ; and Space characters (for good measure, Tab could be removed too) and then replacing commas with x,x.
The result is that the only separators left are commas, and there will be 1 more item in the list so formed than there are commas.
Hence, start the counter at -1 and increment for each element found in the list.
Next solution (similar to Magoo's second method) seems to treat even ˙cmd˙ and .bat poisonous characters supposed in input file:
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "infile=D:\bat\SO\files\35826440input.txt" change to suit your circumstances
set /A "commacount=-1"
for /F "usebackq delims=" %%G in ("%infile%") do (
set "line=%%G"
call :parseline
if /I not "%~1"=="/all" goto :continue
)
:continue
echo script continues here
ENDLOCAL
exit /B
:parseline
rem treat unbalanced doublequote in next line
set "lineToParse=%line:"=§%"
set "lineToParse=%lineToParse:,=","%"
set /A "commacount=-1"
for %%g in ("%lineToParse%") do (
set /A "commacount+=1"
rem echo %line%, !commacount!, %%g
)
echo %commacount% "%line%"
goto :eof
Output (with input file listing):
==> D:\bat\SO\35826440.bat
1 "12345,Bhavik"
script continues here
==> D:\bat\SO\35826440.bat /all
1 "12345,Bhavik"
2 "12323,Bhavik,Sanghvi"
3 "12323,Bhavik,Sanghvi,three"
0 "zero"
1 ",1 leading"
2 ",,2 leading"
1 "trailing,"
2 "2 trailing,,"
2 "2 middle,,mid"
4 "!OS!,!,!!,!!!,exclamations"
4 "%OS%,%,%%%,%%,percents"
8 "&,|,>,<,",",;,=,miscelaneous"
0 "unbalanced"doublequote"
script continues here
==> type D:\bat\SO\files\35826440input.txt
12345,Bhavik
12323,Bhavik,Sanghvi
12323,Bhavik,Sanghvi,three
zero
,1 leading
,,2 leading
trailing,
2 trailing,,
2 middle,,mid
!OS!,!,!!,!!!,exclamations
%OS%,%,%%%,%%,percents
&,|,>,<,",",;,=,miscelaneous
unbalanced"doublequote
==>

Windows Batch Script parsing multiline file with variable line formats?

I need to parse a file that has the following format:
A + tags/RWSTestConsole_tag1/
(from trunk/RWSTestConsole/:r776)
So I'm using a FOR /F loop with a counter and inspecting the tokens based on whether I'm looking at line 1 or line 2. Everything works fine except the first token for line 2 includes the leading spaces (" from") and a) I thought the delims on my FOR would take care of spaces and b) theoretically I could just compare to a constant string that is set to " from" but that's kind of hokey.
This is my FOR command:
for /F "tokens=1,2,3,4,5 delims=():/ " %%a in (svn.txt) DO (
Is there a change I can make to the FOR command to ignore the spaces? If not is there a way to trim the token inside the FOR loop's DO clause so I only get the word without the leading spaces?
Edit:
This is output from a Subversion SVNLOOK command in a script that is managing whether or not to allow a "tag" to be created. The output can be 1 line that must be formatted as:
D /tags/tagfoldername/
If it's one line but it's not a delete for the actual tag folder then it's an error. This case is handled.
If it's more than 2 lines it's a list of files and that's an error. I have that handled.
The case I'm having problems with is if it is 2 lines it needs to be in the format shown above:
A + tags/RWSTestConsole_tag1/
(from trunk/RWSTestConsole/:r776)
Where col 1 = "A". col 3 = "+", col 5 = "tags" and the remainder of line one is the tag folder name. The second line is the source of the create request so it has to start with "from", followed by "trunk", "branches" or "tags" followed by a single-level folder name and a revision number.
I used the FOR command as described above. In the DO clause I look at a counter to tell if I'm parsing line 1 or line 2. Line 1 is simple, I have all the logic to handle it.
Line 2 is parsed by the same FOR command and the first token (%%a) removes the "{" from delims, but leaves behind all the leading blanks so I get back %%a=" from".
I need to know if there's a way I can modify the FOR command to remove the blanks or a way to trim %%a within the FOR DO clause to remove the blanks.
Edit 2: FOR Loop Code
set c=1
for /F "tokens=1,2,3,4,5 delims=():/ " %%a in (svn.txt) DO (
echo op=%%a, %%b, %%c, %%d, %%e
if !c!==1 (
set rc1=0
if /I %%a EQU A (
if "%%b" EQU "+" (
if [%%e] EQU [] (
echo Tag from a Copy Op
set rc1=0
) else (
echo Found a subfolder: %%e - not a tag delete
set rc1=1
)
) else (
echo Tag not a Copy
set rc1=1
)
)
)
if !c!==2 (
set rc2=0
set str1=%%a
echo String replace 1 = !str!
set str2=!str1:~-4!
echo String Replace 2 *!str2!*
if /I !str2! EQU FROM (
set isvalid=false
if %%b EQU trunk set isvalid=true
if %%b EQU branches set isvalid=true
if %%b EQU tags set isvalid=true
if !isvalid! EQU true (
set rc2=0
) else (
set rc2=1
echo Invalid source for Tag Creation
)
) else (
set rc2=1
echo Tag not FROM
)
)
set /a c+=1
)
echo RC1=!rc1!
echo RC2=!rc2!
set /a rc=!rc1!+!rc2!
echo final RC = !rc!

Resources