0

I'm trying to create a batch-File to automate some processes, but as of now, it crashes as soon as it reaches this line

for /L %%i in (1,1,%i%) do (...)

I've tried debugging as much as I could, but only managed to pinpoint the error down to this part. Here's the code leading up to this line:

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
.
.
.
set /p amount="[1] One/[2] Multiple "
if /i "%amount:~,1%" EQU "1" goto one
if /i "%amount:~,1%" EQU "2" goto multiple
:multiple
set /a i=0
for /F "usebackq delims=" %%a in (..\multiple.txt) do (
    set /a i+=1
    set array[!i!]=%%a
)
set /a b=1
echo %i% systems have been detected
for /L %%i in (1,1,%i%) do (
    echo System !b!: IP: !array[%%i]!
    set /a b+=1
)
echo.
echo Please confirm that the input is correct and all systems have been reset to their factory default
set /p confirm="[O]kay/[E]xit "
if /i "%confirm:~,1%" EQU "O" echo Okay
if /i "%confirm:~,1%" EQU "E" goto exit
echo.
echo What type of system are you trying to set up?
echo [0] CPU-Blade
echo [1] GPU-Blade
echo [2] Optic Server
echo [3] Tool Host
echo [4] Provisioning Server
echo [5] Customer Host
echo [6] Control PC
echo [7] Gateway
echo [8] Cluster File Server
echo [9] Storage Expansion Shelf
set /p system="[0]/[1]/[2]/[3]/[4]/[5]/[6]/[7]/[8]/[9] "
set /a b=1
for /L %%i in (1,1,%i%) do (
    echo Resetting Chassis Intrusion for System !b!: !array[%%i]!...

I've thought that maybe the for-Loop executed prior to the crashing one might have some issues with them both using the %%i, so I tried temporarily changing that to %%e, with no success. I also copied another instance of this loop:

for /L %%i in (1,1,%i%) do (
    echo System !b!: IP: !array[%%i]!
    set /a b+=1
)
pause

Right before the crashing loop, but it executed with no problems. I'm at a complete loss right now, any help or pointers would be greatly appreciated!

Korlimann
  • 93
  • 11
  • 1
    What is `for /F "usebackq delims=" %%a in (..\multiple.txt) do (` supposed to do? Are you supposed to be reading lines from the file? Please try a test batch file using just `@(for /F "usebackq delims=" %%a in (..\multiple.txt) do @echo=%%a) & pause` to check that it is doing what it is supposed to be doing. If it is not please open a Command Prompt window, type `for /?`, press the `[ENTER]` key, and read the usage information for that particular command. I would also advise you to stop using `set /p` in situations which the `choice` command was designed to handle, (`choice /?` for more info). – Compo May 19 '21 at 10:39
  • @Compo thanks for the info about choice, I'll be implementing that! The for-Loop in question is simply reading lines from the file(IP Addresses to be exact, 1 address per line with no spaces anywhere). I've created this and the loop after that in a separate test batch file to confirm it's doing what it's supposed to. As far as I'm aware, everything in the code I posted is working as intended, up until it crashes on the third for-Loop. Which confuses me, since I've tested every part leading up to it, and there doesn't seem to be anything obvious wrong. – Korlimann May 19 '21 at 11:03
  • 1
    Did you test it using the single line replacement batch file I suggested? Normally I'd use, `For /F UseBackQ^ Delims^=^ EOL^= %%G In ("..\multiple.txt") Do (`, but for the purposes of showing you the reason I mentioned it, what happens if you change yours to `for /F "usebackq delims=" %%a in ("..\multiple.txt") do (`, or `for /F "delims=" %%a in (..\multiple.txt) do (`? Essentially, if you're using `UseBackQ` double-quote the file, if you don't want to double-quote the file, remove the `UseBackQ`, you're currently doing both, which to me looks wrong! – Compo May 19 '21 at 11:08
  • @Compo thanks for the explanation. I have tried using both examples you provided, but it still crashes on the last for-Loop – Korlimann May 19 '21 at 13:17
  • I am not cotinuing to play guessing games, create two batch files `test1.cmd` and `test2.cmd` and run them from the same location and in the same way as the one you submitted. `test1.cmd` : `@(for /F "usebackq delims=" %%a in (..\multiple.txt) do @echo=%%a) & pause`, and `test2.cmd` : `@(for /F "usebackq delims=" %%a in ("..\multiple.txt") do @echo=%%a) & pause`. What is the output from each? – Compo May 19 '21 at 14:04
  • 1
    A batch file does not crash. A batch file is a simple text file with code which needs to be interpreted by an executable which is `cmd.exe` for a file with file extension `.bat` or `.cmd`. The Windows command processor `cmd.exe` does not crash on processing a batch file. It exits processing a batch file on detecting a serious syntax error making it impossible to continue processing the batch file. That error message can be seen on [debugging a batch file](https://stackoverflow.com/a/42448601/3074564) and also which command line or which command block is responsible for the processing exit. – Mofi May 20 '21 at 05:46
  • 1
    I recommend to read my answer on [How to stop Windows command interpreter from quitting batch file execution on an incorrect user input?](https://stackoverflow.com/a/49834019/3074564) It is no good idea to use `set /P` for user prompts on which the user has to press a key to make a choice of several offered options. There is the command `choice` for choice menus. See also DosTips forum topic: [ECHO. FAILS to give text or blank line - Instead use ECHO/](https://www.dostips.com/forum/viewtopic.php?f=3&t=774) – Mofi May 20 '21 at 05:48
  • 1
    I suggest further reading my answer on [Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files](https://stackoverflow.com/a/47386323/3074564). It explains very detailed how a string comparison is done by `cmd.exe` and why the string comparison operator `==` should be used for string comparisons and not the comparison operator `EQU`. The comparison operator `EQU` is designed primary for an integer comparison on equality and only results in doing a string comparison if `cmd.exe` fails to convert one of the two operands successfully to a 32-bit signed integer. – Mofi May 20 '21 at 05:54
  • 1
    BTW: You make coding work easier for yourself on using meaningful variable names. I recommend to replace `i` (the environment variable `i`) with `LineNumber`. You can already see on doing that why it makes sense to use meaningful variable names. You cannot simple run a search for `i` and replace all occurrences by `LineNumber`. You also cannot easily find out with a simple search where `i` is used as environment variable name and where `i` is used as loop variable. So you have made your coding work unnecessary difficult by not using meaningful and distinctive environment variable names. – Mofi May 20 '21 at 06:01
  • 1
    I recommend further not using an arithmetic expression like `set /a i=0 ` or `set /a b=1` to define an environment variable with a value. That results just in execution of lots of completely unnecessary CPU instructions. Just use `set "i=0"` and `set "b=1"` (with better variable names). For an explanation read my answer on [Why is no string output with 'echo %var%' after using 'set var = text' on command line?](https://stackoverflow.com/a/26388460/3074564) – Mofi May 20 '21 at 06:07
  • 1
    Last but not least the `for /L` loop could be coded also with `for /L %%# in (1,1,%i%) do echo System %%#: IP: !array[%%#]!`. There is no need to use an environment variable `b` if its value is always identical to value of loop variable `#` (or `i` in your code). And there is a line with `)` missing at end of the code. And replace `goto exit` by either `goto :EOF` or `exit /B`. – Mofi May 20 '21 at 06:12
  • @Compo I have run both test1.bat and test2.bat the way you described it. Output from test1 is 192.168.4.10 192.168.4.12 192.168.4.75 192.168.4.103 192.168.4.104 192.168.4.105 and from test2 192.168.4.10 192.168.4.12 192.168.4.75 192.168.4.103 192.168.4.104 192.168.4.105 – Korlimann May 20 '21 at 06:15
  • @Mofi Thank you very much for all the help and info! Regarding the missing `)` I just forgot to include it in the code, my bad! The original for-Loop has a lot more going on after the line where I cut it but I didn't figure it'd be relevant since the program exits before that anyway. Regarding the arithmetic expression, while setting a variable the way you did works, it seems like adding/substracting without using /a does either not work, or I might've gotten the syntax wrong. I'm assuming you still need to use /a for every calculation you want to make? – Korlimann May 20 '21 at 06:39

1 Answers1

0

For anyone else having mysterious problems - turns out the code inside the for-Loop is very relevant indeed. I had an "if" setup to check if one of my variables was empty

if %variable% == []

Batch doesn't like that for some reason. You have to do it like this:

if "%variable%" == []

Otherwise your script will render the whole for-Loop useless and just throw a generic "(" was not expected at this point as soon as it reaches it. Thanks for the help and all info everyone though!

Korlimann
  • 93
  • 11
  • `if "%variable%" == []` will be never true and you know the reason after reading [Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch file](https://stackoverflow.com/a/47386323/3074564). The best method to check if an environment variable with name `variable` is defined at all is using `if not defined variable command` or `if defined variable command`. The help output on running `if /?` in a command prompt window describes that method to check existence of an environment variable. – Mofi May 21 '21 at 19:01
  • You wrote: "Batch doesn't like that for some reason." The batch file does not matter. The batch file is just a text file. The Windows command processor `cmd.exe` is first replacing `%variable%` by current value of the referenced environment variable with name `variable` during [parsing](https://stackoverflow.com/a/49834019/3074564) the command line. So the __IF__ condition becomes `if == []` on `variable` not defined at all. This __IF__ condition with no string left the comparison operator `==` is of invalid syntax and results in an error message on execution of __IF__ and a batch job exit. – Mofi May 21 '21 at 19:10