[simple program that recieves an integer as input and prints if that number is trivial or not]
when i run this i get an error "( was unexpected at this time"
#echo off
set /a i=2
set /p input="enter an integer: "
set /a n=input
set /a t=n/2
:loop1
if %t% LSS %i% (
goto trivial
) else (
set /a t0=n%i
if %t0%==0 (
goto notTrivial
) else (
set /a i=i+1
goto loop1
)
)
:trivial
echo %n% is trivial
goto endd
:notTrivial
echo %n% is not trivial
:endd
pause > nul
but when I remove else statement in loop1 (which is btw unnecessary (because of goto command in if block)) it works
:loop1
if %t% LSS %i% (
goto trivial
)
set /a t0=n%i
if %t0%==0 (
goto notTrivial
) else (
set /a i=i+1
goto loop1
)
(how) is this possible?
When you remove the else clause, the code inside it is now out of any block.
Why does it matter? Because in batch files, lines or blocks of lines (code inside parenthesis) are first parsed and then executed. While parsed variable read operations are removed, being replaced with the value inside the variable at parse time, before starting to execute the command (more here).
So, in this code
) else (
set /a t0=n%i
if %t0%==0 (
goto notTrivial
) else (
set /a i=i+1
goto loop1
)
)
you change the value of the variable t0, but you can not retrieve this changed value inside the same block. But if you remove the else clause the code is not inside a block and everything works as intended (except syntax errors, try with set /a "t0=n %% i").
Firstly, you need to state the modulo operator % as %% in batch files.
Secondly, just move the command set /a t0=n%%i up before the if block begins, then it will work:
:loop1
set /a t0=n%%i
if %t% LSS %i% (
goto trivial
) else (
if %t0% EQU 0 (
goto notTrivial
) else (
set /a i+=1
goto loop1
)
)
So the change of variable t0 is moved outside of a command block ().
Alternatively, you could also enable delayed expansion:
setlocal EnableDelayedExpansion
rem INITIAL CODE PORTION...
:loop1
if %t% LSS %i% (
goto trivial
) else (
set /a t0=n%%i
if !t0! EQU 0 (
goto notTrivial
) else (
set /a i+=1
goto loop1
)
)
rem REMAINING CODE PORTION...
endlocal
You will notice the !t0! type expansion which, in contrast to %t0%, will expand t0 at execution time rather than parse time.
See also setlocal /? and endlocal /? for more information about these commands.
Related
I have two labels in my batch file. The initial label MAIN shall stay in control, so it Calls the second label, which ends with exit /b.
My script's Main label Calls the other, passing it arguments, which will be used to search strings wothin a text file.
When returning to the Calling label, it slways receives an empty return string.
I think this has something to do with the variable expansion in a loop. Who knows?
Here is the Script:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:MAIN
call :getReturnValue "1234 0815 4321 12815" "readBackVal"
if !errorlevel! equ 0 (
echo readback=!readBackVal!
echo readback=%readBackVal%
)
pause
exit /b 0
REM Function, which checks if the give return value is in a specific textfile (line for line check)
:getReturnValue
set "myExpectedValueList=%~1"
set "retval=%~2"
set "file=textexample.txt"
for %%i in (%myExpectedValueList%) do (
for /f "tokens=*" %%a in (%file%) do (
echo %%a|findstr /r "^.*%%i$"
)
if !errorlevel! equ 0 (
(endlocal
set /a "%retval%=%%i")
)
exit /b 0
)
)
exit /b 1
Here is the sample textfile textexample.txt:
Setup returns with errorcode=0815
Here is the answer i looked for:
Hi, first i want to inform that i made some changes due to the Answer of
#OJBakker. This changes are listed at the bottom of the script.
The problem was to return a value from a called function/label to the calling function/label. The stich here is, that the magic
is done in the (endlocal...) section of the called function/label -> means the return of the variable.
Before the endlocal command is executed, the compiler replaces the variables in this section by their values and afterwards executes the command´s from left to right. Means following:
First, the compiler sees following:
(endlocal
if "%retval%" neq "" (call set /a %retval%=%%i)
)
Second, the compiler replaces the variables by their values:
(endlocal
if "readBackVal" neq "" (set /a "readBackVal"=1815)
)
Third: This command is executed
(endlocal
if "readBackVal" neq "" (set /a "readBackVal"=1815)
)
Now here is my complete script (i also fixed some other problems with it which i commented at the bottom of the script
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:MAIN
setlocal
call :getReturnValue "1234 1815 4321 12815" "readBackVal"
if "!errorlevel!" equ "0" (
echo readback=!readBackVal!
)
pause
exit /b 0
REM Function, which checks if the give return value is in a specific textfile (line for line check)
:getReturnValue
setlocal
set "myExpectedValueList=%~1"
set "retval=%~2"
set "file=textexample.txt"
for %%i in (%myExpectedValueList%) do (
for /f "tokens=*" %%a in (%file%) do (
echo %%a|findstr /r "^.*%%i$" >NUL
)
if "!errorlevel!" equ "0" (
(endlocal
if "%retval%" neq "" (set /a %retval%=%%i)
)
exit /b 0
)
)
exit /b 1
REM Changes to initial posting:
REM Added "setlocal" keyword to the function "getReturnValue"
REM Corrected an invalid paranthesis in the (endlocal...) section
REM Changed the file "textexample.txt" -> 0815 to 1815 to remove leading zero (findstr. Problem),
REM Added check, if parameter "retval" has been passed to the called function e.g. is not empty
REM FINAL -> applied double variable expansion (call set /a ...) to return the value proper
REM to the :MAIN function.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:MAIN
call :getReturnValue "1234 0815 4321 12815" "readBackVal"
if %errorlevel% equ 0 (echo readback=%readBackVal%)
pause
endlocal
exit /b 0
REM Function, which checks if the give return value is in a specific textfile (line for line check)
:getReturnValue
set "myExpectedValueList=%~1"
set "retval=%~2"
set "file=textexample.txt"
for %%i in (%myExpectedValueList%) do (
for /f "tokens=*" %%a in (%file%) do (
echo %%a| >con 2>&1 findstr /r "^.*%%i$"
if !errorlevel! equ 0 (
set /a "%retval%=%%i"
exit /b 0
)
)
)
exit /b 1
rem changes:
rem endlocal moved to main.
rem check for errorlevel moved to within the commandblock of the inner for-loop.
rem 'exit /b 0' moved to within the if. This exit line stopped the for after the first item.
rem redirection added to findstr command. Now the output shows the remaining problem.
rem Invalid number. Numeric constants are either decimal (17), hexadecimal (0x11), or octal (021).
rem Findstr really does not like the value 0815, especially the starting zero.
rem I am not sure how to change the regexp so findstr won't barf at the leading zero.
rem Maybe someone else can solve this remaining problem.
This question already has answers here:
Loop through input parameters and array? [duplicate]
Arrays, linked lists and other data structures in cmd.exe (batch) script
(11 answers)
Closed 2 years ago.
I need to loop through the list of files set through the command line, and loop through a local array.
No knowing of a better way, I tried using labels, but cmd doesn't behave as expected:
#echo off
if "%~1"=="" GOTO PARAM
setlocal enableextensions enabledelayedexpansion
set colors[0]="<style>yellow</style>"
set colors[1]="<style>blue</style>"
set COUNTER=0
for %%f in ("%1") DO (
echo Handling %%f
echo !COUNTER!
:LOOP
IF !COUNTER!=="0" GOTO CASE_YELLOW
IF !COUNTER!=="1" GOTO CASE_BLUE
IF !COUNTER! GTR 6 GOTO END
set /a COUNTER +=1
)
GOTO END
:CASE_YELLOW
ECHO Case YELLOW
GOTO LOOP
:CASE_BLUE
ECHO Case BLUE
GOTO LOOP
:PARAM
echo Usage : %0 myfile.xml/*.xml
:END
ECHO Done.
Here's the output using "myscript.bat file*.xml":
Handling file1.xml
0
Handling fileé.xml
1
Done.
Thank you.
Thankfully you put enough info in your code commenting to kinda see where you were going to with the arguments.
that said, if you want to do something when a condition is met in a loop, and continue with the loop after doing it, you simply need to change to calling your sub Functions, and then end of file which will return tou to your place in the loop.
this should do the needful
#(setlocal enableextensions enabledelayedexpansion
echo off
set "colors[0]=<style>yellow</style>"
set "colors[1]=<style>blue</style>"
set /a "COUNTER=0"
SET "SRC=%~1"
)
IF /I "%~1" EQU "" (
Call :PARAM
) ELSE (
CALL :Main
)
( ENDLOCAL
CALL :End
EXIT /B 0
)
:Main
For %%f in ("%SRC%") DO (
IF !COUNTER! < 6 (
echo Handling %%f
echo !COUNTER!
CALL ECHO.IN MAIN LOOP COLOR= "%%Colors[%counter%]%%"
IF !COUNTER!==0 CALL :CASE_YELLOW
IF !COUNTER!==1 CALL :CASE_BLUE
set /a "COUNTER+=1"
) ELSE (
echo.exiting.
GOTO :EOF
)
)
GOTO :EOF
:CASE_YELLOW
ECHO Case YELLOW
ECHO.In sub function yellow COLOR = "!Colors[%counter%]!"
GOTO :EOF
:CASE_BLUE
ECHO Case BLUE
ECHO.In sub function blue COLOR= "!Colors[%counter%]!"
GOTO :EOF
:PARAM
echo Usage : %0 myfile.xml/*.xml
GOTO :EOF
:END
ECHO Done.
Here's the out
GOTO :EOF
I write script like this:
#ECHO OFF
setlocal EnableDelayedExpansion
set "remove=ABC"
echo. %remove%
Set FILENAME="456_789_ABC00011092_789_EFGHIK_56893.mpg"
for %%a in (%FILENAME:_=" "%) do (
set TEN=%%a
echo. %AB%
set "remove_1=ABC"
echo. %remove_1%
Set _TEN=!TEN:%remove%=!
echo. %_TEN%
Set i=0
IF !_TEN! NEQ !TEN! (
set /A i+=1
set "String[!i!]=%%~a"
)
)
pause
exit
Why echo. %AB% echo. %remove_1% result is
I replace % by !. It's work fine but command Set _TEN=!TEN:!remove_1!=! not run
Edit - (from the additional question currently posted as an answer)
When I use FindStr command like this:
for %%a in (%FILENAME:_=" "%) do (
echo %%a | findstr /I /R /C:"ABC" >nul
ECHO %errorlevel%
if "%errorlevel%" equ "0" (
set /A i+=1
set "String[!i!]=%%~a"
)
)
Why errorlevel always = 0
%AB% has not been defined within your posted script, so as it has no value will not be echoed, you will just get an empty line due to the . after echo. Because remove_1 is being set within the loop, (code block), you should be using the delayed expansion syntax, Echo !remove_1!. It is the same for echo. %_TEN%, i.e. Echo !_TEN!, and would have been Echo !AB! had it previously been defined. In order to get the double expansion needed to Set your _TEN variable, you could use a pseudo Call:
#Echo Off
SetLocal EnableDelayedExpansion
Set "FILENAME=456_789_ABC00011092_789_EFGHIK_56893.mpg"
For %%A In ("%FILENAME:_=" "%") Do (
Set "TEN=%%A"
Echo. !AB!
Set "remove_1=ABC"
Echo !remove_1!
Call Set "_TEN=!TEN:%%remove_1%%=!"
Echo !_TEN!
Set "i=0"
If "!_TEN!" NEq "!TEN!" (
Set /A i+=1
Set "String[!i!]=%%~A"
)
)
Pause
Exit /B
In your second related question, initially posted as an answer and now added as an edit to your original question; because the error level is being set within the loop, (code block), you should be using the delayed expansion syntax, !errorlevel!
#Echo Off
SetLocal EnableDelayedExpansion
Set "FILENAME=456_789_ABC00011092_789_EFGHIK_56893.mpg"
For %%A In ("%FILENAME:_=" "%") Do (
Echo %%A | FindStr /IRC:"ABC" >Nul
Echo !errorlevel!
If "!errorlevel!"=="0" (
Set /A i+=1
Set "String[!i!]=%%~A"
)
)
Set String[
Pause
Exit /B
Or if you don't need to Echo each error level to the screen, you can use a conditional statement &&:
#Echo Off
SetLocal EnableDelayedExpansion
Set "FILENAME=456_789_ABC00011092_789_EFGHIK_56893.mpg"
For %%A In ("%FILENAME:_=" "%") Do (
Echo %%A | FindStr /IRC:"ABC" >Nul && (
Set /A i+=1
Set "String[!i!]=%%~A"
)
)
Set String[
Pause
Exit /B
Simply asked, I need to check if a variable is numerical. I'm aware of the ability of:
set /a variable1=%variable%
setting non numerical strings to 0, but i need to be able to have 0 as an intiger as well as negative numbers.
This will be run very often, so a fast script is preferred. I've tried to echo the variable into a .txt, and use a for loop to scan through and return an error if anything other than 0-9 is detected, but the script is excessively long running, and frankly is a mess.
You could do something to this affect. Remove all numbers. If anything is left over it is not an integer. Not saying this is perfect but it is a step in the right direction.
set "tempvar="
FOR /F "tokens=* delims=-0123456789" %%G IN ("%variable1%") DO SET "tempvar=%%G"
IF DEFINED tempvar echo NOT AN INTEGER
As mentioned in question17584282
The easiest for digits should be:
IF %1 NEQ +%1 echo Notnumeric!
If negative numbers (hyphen) are also to be considered, this will work
SET number=%1
if %1 EQU +%1 echo positive number
if %1==-%number:-=% echo negative number
Learned from https://www.itprotoday.com/compute-engines/jsi-tip-9692-how-can-batch-script-determine-if-variable-or-parameter-integer
#echo off
:isInterer input [returnVar]
setlocal enableDelayedexpansion
set "input=%~1"
if "!input:~0,1!" equ "-" (
set "input=!input:~1!"
) else (
if "!input:~0,1!" equ "+" set "input=!input:~1!"
)
for %%# in (1 2 3 4 5 6 7 8 9 0) do (
if not "!input!" == "" (
set "input=!input:%%#=!"
)
)
if "!input!" equ "" (
set result=true
) else (
set result=false
)
endlocal & if "%~2" neq "" (set %~2=%result%) else echo %result%
try this.Some special symbols like ! and ^ could cause trouble though.
You can also use findstr:
#echo off
:isIntererFindstr input [returnVar]
setlocal enableDelayedexpansion
set "input=%~1"
if "!input:~0,1!" equ "-" (
set "input=!input:~1!"
) else (
if "!input:~0,1!" equ "+" set "input=!input:~1!"
)
echo !input!|findstr /r "[^0-9]" >nul 2>&1
if %errorlevel% equ 0 (
set result=false
) else (
set result=true
)
endlocal & if "%~2" neq "" (set %~2=%result%) else echo %result%
My code is
IF "%1" == "-?" (
start randomhelp.bat
) IF NOT DEFINED %1 (goto notdefined) ELSE (
IF NOT DEFINED %2 (goto notdefined) ELSE (
IF NOT DEFINED %3 (goto notdefined) ELSE (
set %1=0
set /a heh=%random% * (%3 - %2 + 1) / 32768 + %2
setx %1=%heh%
) )
:notdefined
However whenever I try to run it is says / was unexpected at this time, however I do not have a / in it except for in the equation. What I'm trying to do is make it so when you type in something like
random randomvalue 1 50
it will set the enviromental variable randomvalue to a random number between 1 and 50. Please help, I have no idea what is wrong with it. Sorry if this seems hard to understand.
#echo off
:: check for help request
if "%~1"=="-?" goto :showHelp
:: check if we have at least three arguments
if "%~3"=="" goto :notDefined
:: check if the second and third arguments are numeric.
for /f "delims=0123456789" %%a in ("%~2") do goto :badArguments
for /f "delims=0123456789" %%a in ("%~3") do goto :badArguments
:: calculate the random value and assign it to exit variable
set "%~1="
set /a "%~1=(%random% %% (%~3 - %~2 + 1)) + %~2" 2>nul
:: if variable does not contain any value, bad data has been
:: feed into script
if not defined %~1 goto :badArguments
goto :eof
:showHelp
echo Usage: %~n0 varName lowValue highValue
goto :eof
:notDefined
echo error: arguments missing
goto :eof
:badArguments
echo error: wrong data in arguments
goto :eof
Well, try this code
IF "%1" == "-?" (
start randomhelp.bat)
IF "%1" == "" (goto notdefined)
IF "%2" == "" (goto notdefined)
IF "%3" == "" (goto notdefined)
set /a heh=%random% * (%3 - %2 + 1)
set /a heh=heh / 32768 + %2
:notdefined
Tip: Arguments are not allowed to be modified, so set %1=0 isn't valid.
I like #Rafael's approach of writing that code as it avoids nested IFs. Anyway though, a couple of things to get it working:
REM You are missing the final parenthesis. Add that!
REM Your second IF statement should be on another line. It could be b/c of copy/paste.
REM Quote the whole expression to avoid that error
IF "%1" == "-?" (
start randomhelp.bat
)
IF NOT DEFINED %1 (goto notdefined) ELSE (
IF NOT DEFINED %2 (goto notdefined) ELSE (
IF NOT DEFINED %3 (goto notdefined) ELSE (
set %1=0
set /a "heh=%random% * (%3 - %2 + 1) / 32768 + %2"
setx %1=%heh%
)))
:notdefined