Breaking out of FOR in batch

Niet the Dark Absol picture Niet the Dark Absol · Mar 27, 2012 · Viewed 13.4k times · Source

My current line of batch code is:

for /L %%a in (8000,1,8100) do netstat /a /n | find "%%a" | find "LISTENING" || set tmp_freeport=%%a && goto found

The idea is to find a free port that will be used for listening, within the range of 8000-8100.

Currently, I have port 8000 in use, so the script should go to 8001.

After the loop, %tmp_freeport% is equal to 8001, as it should be, and its value is used later correctly.

The problem is that the loop keeps running regardless. netstat is called to search for all 101 ports in the range, which is obviously inefficent and unwanted, because the search must complete before the script can continue.

Can anyone tell me how to break out of a batch FOR loop?

(Alternatively, if there's a better way of finding a free port, please see my somewhat-related question)

Answer

dbenham picture dbenham · Mar 27, 2012

You are correct that a FOR /L loop "always" counts to completion. (Well, actually there are some drastic coding methods that can break it, but no need to go there)

However, even though the loop counts to completion, the DO clause is skipped once the GOTO FOUND statement has been executed. You can prove this to yourself by inserting echo testing %%a& in the front of your existing DO clause. You will see that no additional testing takes place once you have found your free port.

The FOR /L loop counts very fast (at least by batch standards), so I wouldn't worry about the extra counting. Now if your were counting 1 through 1 million, then I might worry. At 10 million I am definitely concerned.

I can simplify your existing logic a bit. You can combine the 2 FIND statements into a single FINDSTR using a regular expression.

for /L %%a in (8000,1,8100) do netstat /a /n | findstr /rc:"%%a.*LISTENING" || set tmp_freeport=%%a && goto found

I am no expert concerning IP addresses and ports, but I am concerned that your FIND logic may be inadequate to screen for used ports. I think looking for a colon before and a space after the port will make it more reliable. Also, I doubt you want to see the text of the used ports, so I redirected the FINDSTR output to nul.

for /L %%a in (8000,1,8100) do netstat /a /n | findstr /rc:":%%a .*LISTENING" >nul || set tmp_freeport=%%a && goto found

Note: GOTO :Label will immediately terminate all other forms of a FOR loop. Only the FOR /L variant continues to count after a GOTO.