IF/ELSE block running everything - batch-file

I am making a program to run speed/distance/time calculations. This code works when the surrounding "IF %type%==s(...)" statement is removed, but not when I put it back. It seems to run all the lines? Here's the code:
#ECHO off
COLOR 0f
TITLE Speed Distance Time Calculator
SETLOCAL enabledelayedexpansion
:BEGIN
SET /P type="Calculate speed/distance/time? (S/D/T): "
CLS
IF /I %type%==s (
SET /P distance="Distance: "
CLS
:SDUNITS
SET /P dUnits="Distance units (mile/m/km):"
IF /I "%dUnits%"=="mile" (
SET /a multiply = 0.000621371
) ELSE IF /I "%dUnits%"=="m" (
SET /a multiply = 1
) ELSE IF /I "%dUnits%"=="km" (
SET /a multiply = 0.001
) ELSE (
ECHO "Please type mile/m/km: "
GOTO SDUNITS
)
SET /P time="Time: "
CLS
:STUNITS
SET /P tUnits="Time units (h/m/s):"
IF /I "%tUnits%" == "h" (
SET /a divide = 3600
) ELSE IF /I "%tUnits%" == "m" (
SET /a divide = 60
) ELSE IF /I "%tUnits%" == "s" (
SET /a divide = 1
) ELSE (
ECHO "Please type h/m/s: "
GOTO STUNITS
)
FOR /F %%B IN ('powershell !distance! / !time! * !multiply! / !divide!') DO SET total=%%B
) ELSE (
ECHO "Please type S/D/T"
GOTO BEGIN
)
ECHO !total!
PAUSE
EXIT
Any help would be greatly appreciated.

First, there are a couple of major problems here.
Delayed Expansion issues. As already stated in the comments above, this is a pretty major problem that you'll need to understand better. This alone, I think renders this approach with the giant IF block with nested IF statements impossible in a windows batch program. You'd probably be better off using GOTO (inelegant as it may be):
...
set /p type="Calculate [S]peed, [D]istance, or [T]ime? "
if /i %type%=S (goto calcSpeed)
else if /i %type%=D (goto calcDist)
else if /i %type%=T (goto calcTime)
:calcSpeed
set /p t="Enter the time: "
:EnterTimeUnits
set /p tUnits="Enter the time units - [H]ours, [M]inutes, [S]econds: "
if /i "%tUnits%"=="H" (
set /a divide=3600
) else if /i "%tUnits%"=="M" (
set /a divide=60
) else if /i "%tUnits%"=="S" (
set /a divide=1
) else (
echo Try again.
goto EnterTimeUnits
)
...
Integers only. Also mentioned in the comments above, windows batch variables can only handle integers and strings. No floating point decimal numbers of any kind. You'll have to rearrange your logic so that you can put your multiply value into the powershell command. Something like:
...
if /i "%dUnits%"=="mile" (
for /f %%B IN ('powershell %d%/%t%*0.000621371/%div%') DO SET total=%%B
) else if /i "%dUnits%"=="m" (
for /f %%B IN ('powershell %d%/%t%*1/%div%') DO SET total=%%B
) else if /i "%dUnits%"=="km" (
for /f %%B IN ('powershell %d%/%t%*0.001/%div%') DO SET total=%%B
...
With those out of the way, we can proceed to help with your actual question:
[The] code works when the surrounding IF statement is removed, but not when I put it back. It seems to run all the lines.
I'm not seeing the issue as you describe. However, because of the delayed expansion issues in your nested IF statements, it does some funny looping, asking for the same input twice. I think once you deal with those issues, your other problems will clear up.
Troubleshooting: CLS and #ECHO OFF are great for keeping your console tidy, but they make troubleshooting/debugging your program very difficult. Removing those lines will help you see what's going on.

Related

Getting goto was unexpected at the time

I am currently making a game that has a persuasion system in it. I had all the code for one of the systems set up, but then I set up 2 more, and it started give me an error that said '(number) was not expected at this time'. when I put in 2 for the second choice, and 3 for the 3rd choice.
The code is like this.
#echo off
SETLOCAL EnableDelayedExpansion
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
set "DEL=%%a"
)
set name=Quantum
cls
color 0a
Echo King Redwood: So 2000?
pause >nul
echo.
call :colorText 09 "1. 2500"
echo.
call :colorText 0e "2. 3000"
echo.
call :colorText 0c "3. 4000"
echo.
echo 4. 2000
echo.
set /p "purs=Enter:"
if /i %purs% == 1 (
goto CheckB )
if /i %purs% == 2 (
goto CheckY )
if /i %purs% == 3 (
goto CheckR )
if /i %purs% == 4 (
goto Convo )
:CheckB
set bleu=%random:~-2,1%
if %bleu% GTR 10 (
goto CheckB )
if %bleu% LSS 0 (
goto CheckB )
set /a num = 3
set /a reward = 2500
goto Res
:CheckY
set Yel=%random:~-2,1%
if %Yel% GTR 10 (
goto CheckY )
if %Yel% LSS 0 (
goto CheckY )
set /a num = 5
set reward = 3000
goto Res
:CheckR
set red=%random:~-2,1%
if %red% GTR 10 (
goto CheckB )
if %red% LSS 0 (
goto CheckB )
set /a num = 7
set /a reward = 4000
goto Res
:Convo
set /a reward = 2000
Echo %name%: I think that is a reasonable price.
Echo King Redwood: Very well.
Echo King Redwood: We will now take you to make sure you are
echo ready.
pause >nul
:Res
if %bleu% GEQ %num% goto Succeed
if NOT %bleu% GEQ %num% goto Fail
:Succeed
Echo %name%: I think that the struggles for such a long trip will be more then that
Echo %name%: How about %reward%?
Echo King Redwod: OK %reward% will work.
pause >nul
goto end
:Fail
Echo %name%: I think that you can give me %reward%.
Echo %name%: You know, for the struggles that there will be along the way.
echo If 2000 isn't good enough for you, I'll just have someone else do it.
pause >nul
:end
exit
:colorText
echo off
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1i
First, make sure to close the FOR loop by putting a ) before :CheckB.
For the 'was not expected at this time' error, you're sometimes comparing an empty variable to something. For example, by following CheckY, you set Yel, then proceed to Res and check Bleu, which is empty because it hasn't been set. You're putting nothing next to the binary GEQ operator, and that's why it's complaining.
Tip: to debug, try inserting ECHO statements like this:
:Res
echo bleu=%bleu%,num=%num%
Another problem: when using SET, do not surround the = by spaces. SET /a will work with spaces around =, just because of the nature of /a, but plain SET will not. Well, it will append your variable name with a space and prepend your value with a space, which is not what you want.
Another tip: you can constrain what RANDOM returns through SET /a and the modulus operator, like this.
SET /a red=%random% %% 11
This will set red to a number between 0 and 10, so there is no need for the substrings and goto routines you're using after picking your random number.
Also, consider using EXIT /b to exit the batch file and not the whole CMD environment.

Only accept numeric characters in batch file input

I am making a game from a batch file and one of the inputs can accept any character (~!##$%^&*()`) and any other. Is there any way to look for any character other than numbers and use the GOTO command? This is my script so far:
set /p guess=
echo "%guess%"|findstr /L "[a-z][A-Z]~`!##$%^&*()-_=+\^|^^;:"',<.>/?*"
if %errorlevel% == 0 goto Invalid_Number
if %guess% == %number% goto Correct
... everything else here ...
:Invalid_Number
echo Invalid Number. Input must be a number
pause
Is there any way to make this work, all it says is Access Denied, I am testing this on a school computer though, it might not work.
Put this at the bottom of your script:
:isInt <str>
for /f "delims=0123456789" %%a in ("%1") do exit /b 1
exit /b 0
Then to invoke it, do
call :isInt %guess% && success || fail
Here's a more complete example:
#echo off
setlocal
set /a rand = %RANDOM% %% 10 + 1
:begin
set /P "guess=Guess a number between 1 and 10: "
call :isInt %guess% || goto invalid
if %guess% gtr 0 if %guess% lss 11 (
if %guess% equ %rand% (
echo Lucky guess!
exit /b
) else (
echo Oooh, so close. Try again.
goto begin
)
)
:invalid
echo Please enter a valid integer between 1 and 10.
goto begin
:isInt <str>
for /f "delims=0123456789" %%a in ("%1") do exit /b 1
exit /b 0
This is the same basic idea as MC ND's solution, but instead of using the for statement to unset %guess%, it sets %errorlevel% and stops looping at the first non-numeric character. This makes it infinitesimally more efficient. :)
And with either success or fail, I like to use conditional execution (the && and || stuff).
:ask
set /p "guess=?" || goto :ask
setlocal enabledelayedexpansion
for /f "delims=0123456789" %%a in ("!guess!") do set "guess="
endlocal & set "guess=%guess%"
if not defined guess (
echo invalid input
goto ask
)
echo valid input
The basic idea behind the test is to use the numbers as delimiters in a for /f command, so they are removed from the input. If anything remains it is not a number and the code in the do clause is executed.
The delayedexpansion is enabled/disabled to handle problematic characters (specially double quotes) that could be typed in the input field.
May I suggest you a different, better approach? Instead of read any line and then check if it contains a number, your program may directly read a number, so the checking is not necessary. The way to do that is emulating SET /P command via a subroutine. This way, you may add additional constraints to the input, like read a maximum number of digits, for example.
#echo off
rem Read a number emulating SET /P command
rem Antonio Perez Ayala
setlocal
rem Define the following variable before call InputNumber subroutine
set "thisFile=%~F0"
call :InputNumber number="Enter a number of up to 5 digits: " 5
echo Number read: %number%
goto :EOF
:InputNumber var="prompt" [digits]
setlocal EnableDelayedExpansion
rem Initialize variables
if "%~3" equ "" (set numDigits=9) else set "numDigits=%3"
set "digits=0123456789"
for /F %%a in ('copy /Z "%thisFile%" NUL') do set "CR=%%a"
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
rem Show the prompt and start reading
set /P "=%~2" < NUL
set "input="
set i=0
:nextKey
set "key="
for /F "delims=" %%a in ('xcopy /W "%thisFile%" "%thisFile%" 2^>NUL') do if not defined key set "key=%%a"
rem If key is CR: terminate input
if "!key:~-1!" equ "!CR!" goto endRead
rem If key is BS: delete last char, if any
set "key=!key:~-1!"
if "!key!" equ "!BS!" (
if %i% gtr 0 (
set /P "=!BS! !BS!" < NUL
set "input=%input:~0,-1%"
set /A i-=1
)
goto nextKey
)
rem If key is not a digit: ignore it
if "!digits:%key%=!" equ "%digits%" goto nextKey
rem If can not accept more digits: ignore it
if %i% equ %numDigits% goto nextKey
rem Else: show and accept the digit
set /P "=%key%" < NUL
set "input=%input%%key%"
set /A i+=1
goto nextKey
:endRead
echo/
endlocal & set "%~1=%input%"
exit /B
You may also add any other processing to the input line, like show asterisks instead of digits, etc. For a large example on this topic, see this post

How to check a string does not start with a number in Batch?

How can I check that the first character of a string is a letter and so that it is not a number, or rather a cipher? There are no spaces or special characters in this string.
#ECHO OFF
SETLOCAL
SET /a num=5678
CALL :initnum
SET "num=hello"
CALL :initnum
SET "num=4ello"
CALL :initnum
SET "num=hell0"
CALL :initnum
SET "num=he8lo"
CALL :initnum
SET "num="
CALL :initnum
ECHO(==============
SET /a nam=7654
SET "nem=hello"
SET "nim=4ello"
SET "nom=hell0"
SET "num=he8lo"
SET "nzm="
CALL :initnum2 nam
CALL :initnum2 nem
CALL :initnum2 nim
CALL :initnum2 nom
CALL :initnum2 num
CALL :initnum2 nzm
GOTO :EOF
:initnum
IF NOT DEFINED num ECHO NUM is empty, so it doesn't begin with a numeric&GOTO :EOF
FOR /l %%a IN (0,1,9) DO IF %num:~0,1%==%%a ECHO %num% Begins with numeric&GOTO :EOF
ECHO %num% Does NOT begin with a numeric
GOTO :eof
:initnum2
IF NOT DEFINED %1 ECHO %1 is empty, so it doesn't begin with a numeric&GOTO :EOF
CALL SET "$1=%%%1%%"
FOR /l %%a IN (0,1,9) DO IF %$1:~0,1%==%%a ECHO %1 (%$1%) Begins with numeric&GOTO :EOF
ECHO %1 (%$1%) Does NOT begin with a numeric
GOTO :eof
You should be able to get what you want from this demo.
#echo off
setlocal enableextensions disabledelayedexpansion
set "var=1hello"
for /f "tokens=* delims=0123456789" %%a in ("%var%") do (
if not "%%a"=="%var%" echo var starts with a number
)
If the var contents starts with a number, the token/delim management in the for command will remove it.
edited just to include the usual (included the previous code) and some less used options just in case someone is interested
#echo off
setlocal enableextensions disabledelayedexpansion
set "var=1hello"
echo(%var%
rem Option 1 - Use the for command to tokenize the string
rem A dot is added to handle empty vars
for /f "tokens=* delims=0123456789" %%a in ("%var%.") do (
if not "%%a"=="%var%." (
echo var starts with a number
) else (
echo var does not start with a number
)
)
rem Option 2 - Use set arithmetic and detect errors
rem This will fail if the string starts with + or -
set "%var%_=0"
set /a "test=%var%_" 2>nul
if not errorlevel 1 (
echo var does not start with a number
) else (
echo var starts with a number
)
rem Option 3 - Use substring operations and logic operators
set "test=%var%."
if "%test:~0,1%" GEQ "0" if "%test:~0,1%" LEQ "9" set "test="
if defined test (
echo var does not start with a number
) else (
echo var starts with a number
)
rem Option 4 - Use findstr
rem This is SLOW as findstr needs to be executed
echo(%var%|findstr /b /r /c:"[0-9]" >nul && (
echo var starts with a number
) || (
echo var does not start with a number
)
I think this is the simplest way:
#echo off
setlocal EnableDelayedExpansion
set digits=0123456789
set var=1something
if "!digits:%var:~0,1%=!" neq "%digits%" (
echo First char is digit
) else (
echo First char is not digit
)
The first character of var is tried to be removed from digits string. If such a char was a digit, digits string change; otherwise, digits string remains the same.
#echo off
setlocal
set "the_string=a23something"
for /l %%a in (%the_string% ; 1 ; %the_string%) do set "cl_string=%%~a"
if %the_string:~0,1% neq 0 if "%cl_string%" equ "0" (
echo does not start with number
) else (
echo starts with number
)
endlocal
Another approach is with FINDSTR which eventually will be slower as it is an external for cmd.exe command.
#echo off
set "the_string=something"
echo %the_string%|findstr /b /r "[0-9]" >nul 2>&1 && (
echo starts with number
) || (
echo does not start with number
)
This will work in your situation:
echo %variable%|findstr "^[a-zA-Z]" >nul && echo it starts with an alpha character
Using findstr with regexp :
#echo off
set "$string=2toto"
echo %$string:~0,1%|findstr /i "^-*0*x*[0-9][0-9]*$">nul && echo is NUM || echo Is not NUM
in place of echo is NUM or echo is not NUM you can use a goto to redirect your script the way you want it.
#echo off
set "$string=2toto"
echo %$string:~0,1%|findstr /i "^-*0*x*[0-9][0-9]*$">nul && goto:isnum || goto:isnotnum
:isnum
echo is NUM
exit/b
:isnotnum
echo is not NUM
You have to set the string as a variable; in this way you are able to extract substrings from a main string. Here is an example:
#echo off
set EXAMPLESTRING=12345abcde
set FIRSTCHARACTERSTRING=%EXAMPLESTRING:~0,1%
The result of this short script should be 1 in this case.
Then, you can set a series of conditions to verify whether the first character is a number or not:
if %FIRSTCHARACTERSTRING%==0 goto NUMBER
if %FIRSTCHARACTERSTRING%==1 goto NUMBER
if %FIRSTCHARACTERSTRING%==2 goto NUMBER
if %FIRSTCHARACTERSTRING%==3 goto NUMBER
if %FIRSTCHARACTERSTRING%==4 goto NUMBER
if %FIRSTCHARACTERSTRING%==5 goto NUMBER
if %FIRSTCHARACTERSTRING%==6 goto NUMBER
if %FIRSTCHARACTERSTRING%==7 goto NUMBER
if %FIRSTCHARACTERSTRING%==8 goto NUMBER
if %FIRSTCHARACTERSTRING%==9 goto NUMBER
goto LETTER
:NUMBER
echo The first character is a number!
goto EOF
:LETTER
echo The first character is a letter!
goto EOF
Maybe this is not the most efficient solution but it works fine and it is easier to understand.

Coping with for loop batch file issues when splitting a text file

Good Afternoon!
Long time reader, first time poster! I have been having a lovely time trying to modify a working batch file to account for variability. The situation is that I have a variable-size text document that normally would be able to be split into sections of 252 lines. The code below worked like a champ:
#echo off & setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: batchsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set /A Split=%Full%/252
for /L %%G in (1,1,%Split%) do type nul > "%name%_%%G%.new"
set X=1
set N=1
set Q=1
set limit = 252
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
set /A Q+=1
echo.%%k>> "%name%_!X!%.new"
if !Q! gtr 252 (
set /A X+=1
set /A Q=1
) else if !N! gtr Full (goto theend
)
)
:theend
echo split into %split% files with 252 lines each
rem pause
However, there were some changes to the formatting of the text, and now instead of four pages of 63 lines per split file, it can be completely variable. The only constant is this final line, which precedes the remaining space for a 63 line page:
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
Note that there is a single space in front of it, as well as multiple spaces, a colon, and underscore characters. Being the meathead that I am, I thought I could insert an if-then statement into the for loop to trigger the batch to split to the next page. However, I could be further from that right now. This is the code I have been smashing my head with:
rem #echo off & setlocal EnableDelayedExpansion
setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: textsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set Name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set stopvar= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
set Split=1
echo %stopvar%
set X=1
type nul > "%name%_!X!%.new"
set N=1
set Q=1
set S=0
set L=63
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
echo %N%
set /A Q+=1
echo %Q%
echo.%%k>> "%name%_!X!%.new"
if ["%%k%" == "!stopvar!"] (
set /A S+=1
)
if !Q! gtr !L! (
if !S! == 1 (
set /A X+=1
set /A Q=1
type nul > "%name%_!X!%.new"
set /A Split+=1
set S=0
)
else set /A L+=63
else if !N! gtr Full goto theend
)
:theend
echo Split into %split% files!
pause
The premise is that every 63 lines, the stop variable (S) is checked. If it is off (0) then the batch will continue to write for another 63 lines (one page). If the stopvar matches the line that is being read by the for loop, S becomes 1. When the program checks again, it will create a new file and begin writing to that new file. Right now, based on turning off #echo off the hangup is at the for loop. See below:
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rrtextsplit texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rem #echo off & setlocal Enabl
eDelayedExpansion
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>setlocal EnableDelayedExpansio
n
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not defined param (
echo.
echo. Usage: rrtextsplit [device:][pathname]filename
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not exist "texttest.txt" (
echo.
echo. File "texttest.txt" not found
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for %j in ("texttest.txt") do
(
set Name=%~dpnj
set ext=%~xj
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>(
set Name=C:\Users\theangryasiancp\Desktop\TEXT_Split_Test\texttest
set ext=.txt
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for /F %j in ('type "texttest.
txt" | find /V /C ""') do set Full=%j
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Full=567
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set stopvar= ON THIS FORM IS C
OMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Split=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>echo ON THIS FORM IS COMPLETE
AND CORRECT AS NOTED:___________________
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set X=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>type nul 1>"C:\Users\theangry
asiancp\Desktop\RRRR_Split_Test\texttest_!X!.new"
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set N=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Q=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set S=0
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set L=63
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>
What are your thoughts? Where am I going wrong with the batch? I wish I could use something different, but alas I cannot, for internal company reasons. Thanks for your help!
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "name=q23396663"
SET "ext=.txt"
SET /a pagelength=10
SET "targetstring= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
SET /a filenum=0
SET /a linecount=pagelength + 1
FOR /f "tokens=1*delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
IF !linecount! GEQ %pagelength% (
SET /a linecount=0
SET /a filenum+=1
)
>>U:\%name%_!filenum!.new ECHO(%%b
IF "%%b"=="%targetstring%" SET /a linecount=pagelength
SET /a linecount+=1
)
GOTO :EOF
For testing purposes, I set up a file q23396663.txt containing your trigger data. I've left the destination directory as U:\ which suits me, and the pagelength at 10 which makes my testing easier.
#echo off
setlocal EnableDelayedExpansion
REM ------------------THIS SECTION SPECIFIES THE FILE-------------------------
set param=%*
if not defined param (
echo.
echo. Usage: filesplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
GOTO :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
ECHO SPLITTING %name%.%ext% .................
REM ----------------THIS SECTION SETS THE VARIABLES---------------------------
set "trigger= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
set /a pagelength=63
set /a filenum=0
set split=1
set /a linecount=pagelength
set stopvar=0
REM ------------------THIS SECTION IS THE FOR LOOP----------------------------
FOR /f "skip=2 tokens=1* delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
SET /a linecount-=1
IF !linecount! LEQ 0 (
IF !stopvar! EQU 1 (
SET /a "linecount=pagelength"
SET /a filenum+=1
SET /a split+=1
SET /a stopvar-=1
) else set /a "linecount=pagelength"
)
echo.%%b>> "%name%_!filenum!.new"
IF "%%b"=="%trigger%" (
set /a "stopvar+=1"
REM THIS TRIGGERS TO CHANGE OUTPUT
set /a linecount+=1
REM THIS WILL ADJUST THE OUTPUT EOF
)
)
REM ----------------THIS SECTION ENDS THE FOR LOOP----------------------------
ECHO Split into %split% files!
ping 1.1.1.1 -n 1 -w 2500 > nul
REM THIS PAUSES THE BATCH FOR A SEC
As I posted in the comment above, this is just a variation of the first answer that accounts for blank spaces if they are needed to keep the output files from having unnecessary whitespace on top. This is especially helpful when a print manager is just spitting out whitespace until the end of the page before starting the next part instead of going straight to the next portion.

FOR /F issue running from a text file + counting up value

Here is something I'm struggeling with:
Title Scanning online computers: && set /a title_count=0
call :next
:next
FOR /F "tokens=1" %%a IN (workstation.txt) do (
title Scanning for online computers: %title_count% / %workstation%
ping -n 1 %%a | find "bytes=" >nul
set /a title_count=title_count+=1
if NOT ERRORLEVEL 1 (
set color=%%a && call includes\what.bat %color_pass% && echo %%a >> logs\reachable.txt
) else (
set color=%%a && call includes\what.bat %color_fail% && echo %%a >> logs\unreachable.txt && echo %%a, offline, % date%, %time% >> logs\offline.txt
)
)
The problem I have here is that the function TITLE is not getting updated while the variable %count_title% is counting up through the script.
set /a title_count+=1
doesn't work either
It's displayed as:
Scanning for online computers 0 / 5
Can sombody tell me what I'm doing wrong here?
Thanks in advance.
Illusion
Hi,
I've tried it the way as suggested:
It finishes the rest of the script when using the last GOTO :EOF
IT doesn't make sense to me, if I remove the last GOTO :eof, only the first row in workstation.txt is getting processed/parsed.
Scanning online computers: && set /a title_count+=1`
call :next
::added as possibly missing
GOTO :EOF
:next
FOR /F "tokens=1" %%a IN (workstation.txt) DO CALL :pingstation %%a
GOTO :EOF
:pingstation
title Scanning for online computers: %title_count% / %workstation%
ping -n 1 %1 | find "bytes=" >nul
set /a title_count+=1
if NOT ERRORLEVEL 1 (
set color=%1 && call includes\what.bat %color_pass% && echo %1 >> logs\reachable.txt
) else (
set color=%1 && call includes\what.bat %color_fail% && echo %1 >> logs\unreachable.txt && echo %1, offline, %date%, %time% >> logs\offline.txt
)
goto :eof
)
Read this: Environment variable expansion occurs when the command is read.
Salient points:
Your variables are expanded right when for command (and its entire body enclosed in parentheses) is parsed.
Use !VARNAME! instead of %VARNAME% to avoid it.
For better portability across OS versions/setups, it's a good idea to stick a setlocal EnableExtensions EnableDelayedExpansion at the beginning of your batch file.
Also, make sure there is a goto (e.g., goto :EOF) after call :next, because the code as posted will run through next one extra time.
You can go with setlocal EnableDelayedExpansion and changing the % syntax to the ! one when addressing vars inside the loop that are initialised within that very loop, just as atzz has suggested.
But there's a different approach. You can simply move the body of the loop to a(nother) subroutine. That way the variables would expand as expected.
Title Scanning online computers: && set /a title_count=0
call :next
::added as possibly missing
GOTO :EOF
:next
FOR /F "tokens=1" %%a IN (workstation.txt) DO CALL :pingstation %%a
GOTO :EOF
:pingstation
title Scanning for online computers: %title_count% / %workstation%
ping -n 1 %1 | find "bytes=" >nul
set /a title_count+=1
if NOT ERRORLEVEL 1 (
set color=%1 && call includes\what.bat %color_pass% && echo %1 >> logs\reachable.txt
) else (
set color=%1 && call includes\what.bat %color_fail% && echo %1 >> logs\unreachable.txt && echo %1, offline, %date%, %time% >> logs\offline.txt
)

Resources