What is wrong with this batch script? - windows

I need a batch that reads a number from a file, increments it and saves it back into this file... This is what I came up with:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
IF EXIST script\BUILDVERSION (
SET /p input = <script\BUILDVERSION
SET /a result=%input%+1
ECHO %result% > script\BUILDVERSION
) ELSE (
ECHO 0 > script\BUILDVERSION
)
At first it worked in a strange way, the result from reading the number from the file seemed to be a small random number, the result of the sum seemed random too... I don't know what I did, but now it doesn't even read the number from file into the variable...
Thanks in advance for help!

Instead of %input% and %result%, try using !input! and !result!. This seems to work better when using delayed expansion. Also, make sure you don't have any unnecessary spaces when reading from the file. You'll end up with:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
IF EXIST script\BUILDVERSION (
SET /p input=<script\BUILDVERSION
SET /a result=!input!+1
ECHO !result! > script\BUILDVERSION
) ELSE (
ECHO 0 > script\BUILDVERSION
)

Related

If syntax in windows batch

I'm trying to make this work in a windows batch file:
if not exist "%~n1.ext" (
set /P z="PROMPT (y,n)?"
if /i "%z%" == "y" (
echo if is working
)
)
But no matter what the input is, it never goes into the echo part. Is there something wrong in the syntax?
When you use a variable inside a block (between (and ), you need to enable delayed expansion:
setlocal enabledelayedexpansion
set var=hello
if "a"=="a" (
set var=world
echo %var% !var!
)
Stephan is correct, you need to use enabledlayedexpansion when using a nested variable. Here's your code with that syntax (replacing % with ! when using such variables):
setlocal enabledelayedexpansion
if not exist "%~n1.ext" (
set /P z="PROMPT (y,n)?"
if /i "!z!" == "y" (
echo if is working
)
)

Unable to echo user input values to file in Batch script

I am writing a batch file that will generate/write to a property file based on multiple user input values. However, it is not recording the values of input. The result looks like
prop1=
prop2=
I wonder if there's something I need to know with set that is preventing this from working.
Weird part is that if I run this particular script multiple times, the value output from echo seems to be always be the user input from last time.
Code:
#echo off
IF NOT EXIST data_file (
set /p prop1=Enter value:
set /p prop2=Enter value:
(echo prop1=%prop1%) > data_file
(echo prop2=%prop2%) >> data_file
)
Classic problem for inexperienced batchers :)
%prop1% is expanded when the line is parsed. Your problem is that everthing within parentheses is parsed in one pass. So the value you see is the value that existed before you entered the IF statement.
You have two simple solutions.
1) Eliminate the enclosing parens by reversing the logic and using GOTO
#echo off
IF EXIST file goto skip
set /p prop1=Enter value:
set /p prop2=Enter value:
(echo prop1=%prop1%) >file
(echo prop2=%prop2%) >>file
:skip
2) Use delayed expansion - that takes place just before each line within the parens is executed
#echo off
setlocal enableDelayedExpansion
IF NOT EXIST file (
set /p prop1=Enter value:
set /p prop2=Enter value:
(echo prop1=!prop1!)>file
(echo prop2=!prop2!)>>file
)
You need to expand the variables using SETLOCAL ENABLEDELAYEDEXPANSION or use CALL.
#echo off
IF NOT EXIST data_file (
set /p prop1=Enter value:
set /p prop2=Enter value:
(
Call echo prop1=%%prop1%%
Call echo prop2=%%prop2%%
) > data_file
)

how to do loop in Batch?

I want to create something like this
dup.bat infile outfile times
example usage would be
dup.bat a.txt a5.txt 5
at it would create file a5.txt that has the content of a.txt repeated 5 times
however I do not know how to do for loop in batch, how to do it?
You can do the loop like this:
SET infile=%1
SET outfile=%2
SET times=%3
FOR /L %%i IN (1,1,%times%) DO (
REM do what you need here
ECHO %infile%
ECHO %outfile%
)
Then to take the input file and repeat it, you could use MORE with redirection to append the contents of the input file to the output file. Note this assumes these are text files.
#ECHO off
SET infile=%1
SET outfile=%2
SET times=%3
IF EXIST %outfile% DEL %outfile%
FOR /L %%i IN (1,1,%times%) DO (
MORE %infile% >> %outfile%
)
For command line args
set input=%1
set output=%2
set times=%3
To do a simple for loop, read in from the input file, and write to the output file:
FOR /L %%i IN (1,1,%times%) DO (
FOR /F %%j IN (%input%) DO (
#echo %%j >> %output%
)
)
Instead of taking in an output file, you could also do it via command line:
dup.bat a.txt 5 > a5.txt
sigh
Compact Design:
SETLOCAL ENABLEDELAYEDEXPANSION
SET times=5
:Beginning
IF %times% NEQ 0 (TYPE a.txt>>a5.txt & SET /a times=%times%-1 & GOTO Beginning) ELSE ( ENDLOCAL & set times= & GOTO:eof)
Easy Reading:
SETLOCAL ENABLEDELAYEDEXPANSION
SET times=5
:Beginning
IF %times% NEQ 0 (
TYPE a.txt>>a5.txt
SET /a times=%times%-1
GOTO Beginning
) ELSE (
ENDLOCAL
set times=
GOTO:eof
)
Set your counter (times=5)
Start subroutine Beginning
If your counter doesn't equal 0, read a.txt and APPEND its contents to a5.txt, then decrement your counter by 1. This will repeat five times until your counter equals 0, then it will cleanup your variable and end the script.
SET ENABLEDELAYEDEXPANSION is important to increment variables within loops.

Batch script loop

I need to execute a command 100-200 times, and so far my research indicates that I would either have to copy/paste 100 copies of this command, OR use a for loop, but the for loop expects a list of items, hence I would need 200 files to operate on, or a list of 200 items, defeating the point.
I would rather not have to write a C program and go through the length of documenting why I had to write another program to execute my program for test purposes. Modification of my program itself is also not an option.
So, given a command, a, how would I execute it N times via a batch script?
Note: I don't want an infinite loop
For example, here is what it would look like in Javascript:
var i;
for (i = 0; i < 100; i++) {
console.log( i );
}
What would it look like in a batch script running on Windows?
for /l is your friend:
for /l %x in (1, 1, 100) do echo %x
Starts at 1, steps by one, and finishes at 100.
WARNING: Use %% instead of %, if it's in a batch file, like:
for /l %%x in (1, 1, 100) do echo %%x
(which is one of the things I really really hate about windows scripting.)
If you have multiple commands for each iteration of the loop, do this:
for /l %x in (1, 1, 100) do (
echo %x
copy %x.txt z:\whatever\etc
)
or in a batch file
for /l %%x in (1, 1, 100) do (
echo %%x
copy %%x.txt z:\whatever\etc
)
Key:
/l denotes that the for command will operate in a numerical fashion, rather than operating on a set of files
%x is the loops variable
(starting value, increment of value, end condition[inclusive] )
And to iterate on the files of a directory:
#echo off
setlocal enableDelayedExpansion
set MYDIR=C:\something
for /F %%x in ('dir /B/D %MYDIR%') do (
set FILENAME=%MYDIR%\%%x\log\IL_ERROR.log
echo =========================== Search in !FILENAME! ===========================
c:\utils\grep motiv !FILENAME!
)
You must use "enableDelayedExpansion" and !FILENAME! instead of $FILENAME$. In the second case, DOS will interpret the variable only once (before it enters the loop) and not each time the program loops.
Template for a simple but counted loop:
set loopcount=[Number of times]
:loop
[Commands you want to repeat]
set /a loopcount=loopcount-1
if %loopcount%==0 goto exitloop
goto loop
:exitloop
Example: Say "Hello World!" 5 times:
#echo off
set loopcount=5
:loop
echo Hello World!
set /a loopcount=loopcount-1
if %loopcount%==0 goto exitloop
goto loop
:exitloop
pause
This example will output:
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Press any key to continue . . .
You could also try this instead of a for loop:
set count=0
:loop
set /a count=%count%+1
(Commands here)
if %count% neq 100 goto loop
(Commands after loop)
It's quite small and it's what I use all the time.
You could do something to the following effect avoiding the FOR loop.
set counter=0
:loop
echo "input commands here"
SET /A counter=%counter%+1
if %counter% GTR 200
(GOTO exit) else (GOTO loop)
:exit
exit
Or you can decrement/increment a variable by the number of times you want to loop:
SETLOCAL ENABLEDELAYEDEXPANSION
SET counter=200
:Beginning
IF %counter% NEQ 0 (
echo %x
copy %x.txt z:\whatever\etc
SET /A counter=%counter%-1
GOTO Beginning
) ELSE (
ENDLOCAL
SET counter=
GOTO:eof
Obviously, using FOR /L is the highway and this is the backstreet that takes longer, but it gets to the same destination.
Very basic way to implement looping in cmd programming using labels
#echo off
SET /A "index=1"
SET /A "count=5"
:while
if %index% leq %count% (
echo The value of index is %index%
SET /A "index=index + 1"
goto :while
)
You can do this without a for statement ^.^:
#echo off
:SPINNER
SET COUNTP1=1
:1
CLS
:: YOUR COMMAND GOES HERE
IF !COUNTP1! EQU 200 goto 2
SET COUNTP1=1
) ELSE (
SET /A COUNTP1+=1
)
goto 1
:2
:: COMMAND HAS FINISHED RUNNING 200 TIMES
It has basic understanding. Just give it a test. :P
DOS doesn't offer very elegant mechanisms for this, but I think you can still code a loop for 100 or 200 iterations with reasonable effort. While there's not a numeric for loop, you can use a character string as a "loop variable."
Code the loop using GOTO, and for each iteration use SET X=%X%# to add yet another # sign to an environment variable X; and to exit the loop, compare the value of X with a string of 100 (or 200) # signs.
I never said this was elegant, but it should work!
I use this. It is just about the same thing as the others, but it is just another way to write it.
#ECHO off
set count=0
:Loop
if %count%==[how many times to loop] goto end
::[Commands to execute here]
set count=%count%+1
goto Loop
:end
The answer really depends on how familiar you are with batch, if you are not so experienced, I would recommend incrementing a loop variable:
#echo off
set /a loop=1
:repeat
echo Hello World!
set /a loop=%loop%+1
if %loop%==<no. of times to repeat> (
goto escapedfromrepeat
)
goto repeat
:escapedfromrepeat
echo You have come out of the loop
pause
But if you are more experienced with batch, I would recommend the more practical for /l %loop in (1, 1, 10) do echo %loop is the better choice.
(start at 1, go up in 1's, end at 10)
for /l %[your choice] (start, step, end) do [command of your choice]
a completely flawless loop
set num=0
:loop
:: insert code
set /a num=%num%+1
if %num% neq 10 goto loop
::insert after code code
you can edit it by changing the 10 in line 5 to any number to represent how many time you want it to loop.
Not sure if an answer like this has already been submitted yet, but you could try something like this:
#echo off
:start
set /a var+=1
if %var% EQU 100 goto end
:: Code you want to run goes here
goto start
:end
echo var has reached %var%.
pause
exit
The variable %var% will increase by one until it reaches 100 where the program then outputs that it has finished executing. Again, not sure if this has been submitted or something like it, but I think it may be the most compact.
Use FOR /l and make sure to use %% instead of %
It will save you headaches.
And try to Set the loop.
(EDITED) I made it so it stops after 100 times
#echo off
goto actual
set /a loopcount=0
:actual
set /a loopcount=%loopcount% + 1
echo %random% %random% %random% %random%
timeout 1 /nobreak>nul
if %loopcount%== 100 goto stop
goto actual
:stop
exit
This will generate 4 random numbers ever 1 second 100 times.
Take out the "timeout 1 /nobreak>nul" to make it go super fast.
I have 2 answers
Methods 1:
Insert Javascript into Batch
#if (#a==#b) #end /*
:: batch portion
#ECHO OFF
cscript /e:jscript "%~f0"
:: JScript portion */
Input Javascript here
( I don't know much about JavaScript )
Method 2:
Loop in Batch
#echo off
set loopcount=5
:loop
echo Hello World!
set /a loopcount=loopcount-1
if %loopcount%==0 goto exitloop
goto loop
:exitloop
pause
(Thanks FluorescentGreen5)

Batch File input validation - Make sure user entered an integer

I'm experimenting with a Windows batch file to perform a simple operation which requires the user to enter a non-negative integer. I'm using simple batch-file techniques to get user input:
#ECHO OFF
SET /P UserInput=Please Enter a Number:
The user can enter any text they want here, so I would like to add some routine to make sure what the user entered was a valid number. That is... they entered at least one character, and every character is a number from 0 to 9. I'd like something I can feed the UserInput into. At the end of the routine would be like an if/then that would run different statements based on whether or not it was actually a valid number.
I've experimented with loops and substrings and such, but my knowledge and understanding is still slim... so any help would be appreciated.
I could build an executable, and I know there are nicer ways to do things than batch files, but at least for this task I'm trying to keep it simple by using a batch file.
You're probably not doing this in a DOS batch file. Or at least, support for set /p is unheard of for me in DOS :-)
You could use substrings. In fact I have written a parser for a specific regular language that way once, but it's cumbersome. The easiest way would probably be to assign the contents of %userinput% to another variable, using set /a. If the result comes out as 0 you need to check whether the input itself was 0, otherwise you can conclude it was a non-number:
#echo off
setlocal enableextensions enabledelayedexpansion
set /p UserInput=Enter a number:
set /a Test=UserInput
if !Test! EQU 0 (
if !UserInput! EQU 0 (
echo Number
) else (
echo Not a number
)
) else (
echo Number
)
However, this works only for numbers in the range of Int32. If you just care for any number (possibly floating-point as well) then you need to resort to the loop-based approach of dissecting it.
NOTE: Updated to solve the space issues. However, there is still a problem lurking: Entering 123/5 yields "number", since set /a can evaluate this ...
Thanks all. I was trying to make it harder for myself looking at loops and string manipulation. I used your tips on math evaluation and comparison. Here's what I finally came up with as my concept script:
:Top
#ECHO OFF
ECHO.
ECHO ---------------------------------------
SET /P UserInput=Please Enter a Number:
ECHO.
ECHO UserInput = %UserInput%
ECHO.
SET /A Evaluated=UserInput
ECHO Math-Evaluated UserInput = %Evaluated%
if %Evaluated% EQU %UserInput% (
ECHO Integer
IF %UserInput% GTR 0 ( ECHO Positive )
IF %UserInput% LSS 0 ( ECHO Negative )
IF %UserInput% EQU 0 ( ECHO Zero )
REM - Other Comparison operators for numbers
REM - LEQ - Less Than or Equal To
REM - GEQ - Greater Than or Equal To
REM - NEQ - Not Equal To
) ELSE (
REM - Non-numbers and decimal numbers get kicked out here
ECHO Non-Integer
)
GOTO Top
This method catches all numbers and can detect whether it's positive, negative, or zero. Any decimal or string will be detected as non-integers. The only edge case I've found is a string with spaces. For example, the text "Number 1" will cause the script to crash/close when the user input is evaluated as math. But in my situation, this is fine. I don't want my script to go on with invalid input.
You can also use a quite simple trick:
echo %userinput%|findstr /r /c:"^[0-9][0-9]*$" >nul
if errorlevel 1 (echo not a number) else (echo number)
This uses findstr's regular expression matching capabilities. They aren't very impressive but useful at times.
This is the same idea as that of Johannes..
SET /A sets a numeric value. If the input is not a number, it changes it to 0.
That's what you can exploit here to do your check.
#ECHO OFF
SET /P UserInput=Please Enter a Number:
IF %UserInput% EQU 0 GOTO E_INVALIDINPUT
SET /A UserInputVal="%UserInput%"*1
IF %UserInputVal% GTR 0 ECHO UserInput "%UserInputVal%" is a number
IF %UserInputVal% EQU 0 ECHO UserInput "%UserInputVal%" is not a number
GOTO EOF
:E_INVALIDINPUT
ECHO Invalid user input
:EOF
As an alternative, you could always create a little javascript file and call it from your batchfile. With parseInt() you could force the input to be an integer, or you could roll your own function to test the input.
Writing the javascript is just as fast as the batchfile, but it's much more powerful. No IDE or compiler required; notepad will do. Runs on every windows box, just like your batchfiles. So why not make use of it?
You can even mix batchfiles and javascript. Example:
contents of sleep.js:
var SleepSecs=WScript.Arguments.Item(0);
WScript.Sleep(SleepSecs*1000)
contents of sleep.cmd:
cscript /nologo sleep.js %1
You can now call this from a batchfile to make your script sleep for 10 seconds. Something like that is difficult to do with just a plain batchfile.
sleep 10
As pointed out by ghostdog74, the answers posted by Joey Mar 26 '09 (score 10) and Wouter van Nifterick Mar 26 '09 (score 5) don't work.
The answer posted by Joey Mar 25 '10 (score 2) does work, except that redirection symbols and '&' cause syntax errors.
I think the best and simplest solution is the one posted by Sager Oct 8 '14 (score 0). Unfortunately, it has a typo: ‘"%a"’ should be ‘"%a%"’.
Here's a batch file based on Sager's answer. Redirection symbols and '&' in the input don't cause problems. The only problems I could find were caused by strings containing double quotes.
#echo off & setlocal enableextensions & echo.
set /p input=Enter a string:
SET "x=" & for /f "delims=0123456789" %%i in ("%input%") do set x=%%i
if defined x (echo Non-numeral: "%x:~0,1%") else (echo No non-numerals)
In addition to the remark about the error that occures when spaces are part of the users input. You can use errorlevel errorlevel=9165. It can be used for the spaces in a string or for the error handling of 'no' input.
Kind Regards,
Egbert
You might also like this one - it's short and easy. This one use the multiplication trick to set TestVal. Comparing TestVal against UserInput allows all numeric values to get through including zeroes, only non-numerics will trigger the else statement. You could aslo set ErrorLevel or other variables to indicate a failed entry
#ECHO OFF
SET TestVal=0
SET /P UserInput=Please Enter a Number:
SET /A TestVal="%UserInput%"*1
If %TestVal%==%UserInput% (
ECHO You entered the number %TestVal%
) else ECHO UserInput "%UserInput%" is not a number
GOTO EOF
:EOF
I know this is years old, but just to share my solution.
set /p inp=Int Only :
:: Check for multiple zeros eg : 00000 ::
set ch2=%inp%-0
if %inp% EQU 0 goto :pass
if [%inp%]==[] echo Missing value && goto :eof
if %inp:~0,1%==- echo No negative integers! && goto :eof
set /a chk=%inp%-10>nul
if %chk%==-10 echo Integers only! && goto :eof
:pass
echo You shall pass
:eof
Tested and working on Windows 8.
you can reinvent the wheel and grow a few white hairs doing string validation in batch, or you can use vbscript
strInput = WScript.Arguments.Item(0)
If IsNumeric(strInput) Then
WScript.Echo "1"
Else
WScript.Echo "0"
End If
save it as checkdigit.vbs and in your batch
#echo off
for /F %%A in ('cscript //nologo checkdigit.vbs 100') do (
echo %%A
rem use if to check whether its 1 or 0 and carry on from here
)
You can validate any variable if its number:
SET "var="&for /f "delims=0123456789" %i in ("%a") do set var=%i
if defined var (echo."NIC">nul) else (echo."number")
If you want some sort of a loop and default set up for that particular question, then here's my method for doing this.
Notes on the code within.
#echo off
setlocal EnableDelayedExpansion
set "ans1_Def=2"
:Q1
set /p "ans1=Opt 1 of 1 [Value 1-5 / Default !ans1_Def!]: "
:: If not defined section. This will use the default once the ENTER key has been
:: pressed and then go to :Q2.
if not defined ans1 (
echo/ & echo ENTER hit and the default used. Default is still: !ans1_Def! & echo/
set "ans1=!ans1_Def!" && goto :Q2 )
:: This section will check the validity of the answer. The "^[1-5]$" will work
:: for only numbers between one and five in this example but this can be changed
:: to pretty much suit the majority of cases. This section will also undefine
:: the ans1 variable again so that hitting the ENTER key at the question
:: will work.
echo %ans1%|findstr /r /c:"^[1-5]$" >nul
if errorlevel 1 (
echo/ & echo At errorlevel 1. Wrong format used. Default is still: !ans1_Def! & echo/
set "ans1=" && goto Q1
) else ( echo Correct format has been used. %ans1% is the one. && goto :Q2 )
:Q2
echo/
echo -----------------------------
echo/
echo Now at the next question
echo !ans1!
echo/
pause
exit
Try this:
set /p numeric=enter a number
(
(if errorlevel %numeric% break ) 2>nul
)&&(
echo %numeric% is numeric
)||(
echo %numeric% is NOT numeric
)
Just try this
#echo off
SET constNum=100
:LOOP
Set /p input=Please input a number less than %constNum% :
if "%input%" == "" echo Blank is not allowed & goto LOOP
SET "notNumChar="
for /f "delims=0123456789" %%i in ("%input%") do set notNumChar=%%i
if defined notNumChar (
echo %input% is a string
goto LOOP
) else (
REM Remove leading 0 if it has. eg: 08→8
FOR /F "tokens=* delims=0" %%A IN ("%input%") DO SET inputNum=%%A
)
REM Compare
if defined inputNum (
echo %inputNum%
if %inputNum% equ %constNum% & goto LOOP
if %inputNum% gtr %constNum% & goto LOOP
if %inputNum% lss %constNum% & goto CONTINUE
)
:CONTINUE
:: Your code here
:ASK
SET /P number= Choose a number [1 or 2]:
IF %number% EQU 1 GOTO ONE
IF %number% NEQ 1 (
IF %number% EQU 2 GOTO TWO
IF %number% NEQ 2 (
CLS
ECHO You need to choose a NUMBER: 1 OR 2.
ECHO.
GOTO ASK
)
)
It works fine to me. If he chooses numbers less or greater, strings, floating number etc, he wil receive a message ("You need to choose a NUMBER: 1 OR 2.") and the INPUT will be asked again.
#echo off
setlocal enableextensions enabledelayedexpansion
set /p UserInput=Enter a number:
set /a Test=UserInput
if !Test! EQU 0 (
if !UserInput! EQU 0 (
echo Number
) else (
echo Not a number
)
) else (
echo Number
)
yeaph everthing is great
but you forget about one little thing
0 also is a digit
;(
This is more of a user friendly way.
if %userinput%==0 (
cls
goto (put place here)
)
if %userinput%==1 (
cls
goto (put place here)
)
if %userinput%==2 (
cls
goto (put place here)
)
if %userinput%==3 (
cls
goto (put place here)
)
if %userinput%==4 (
cls
goto (put place here)
)
if %userinput%==5 (
cls
goto (put place here)
)if %userinput%==6 (
cls
goto (put place here)
)if %userinput%==7 (
cls
goto (put place here)
)
if %userinput%==8 (
cls
goto (put place here)
)
if %userinput%==9 (
cls
goto (put place here)
)
This can be used for any type of user input.
for me this is working for all non-zero values ..should i be cautious of some rare cases?
set /a var = %1
if %var% neq 0 echo "it is number"
pause

Resources