Batch comma separated values

I have a script I'm working on that I input IP Addresses, and checks that it's valid. I figured out how to do a range, but I would also like to use commas to enter discontinuous ip addresses, such as 10.10.10.1,12,15,20,100 and then have it validated and echo this to my txt file like this

10.10.10.1
10.10.10.12
10.10.10.15
10.10.10.20
10.10.10.100

I think I have an idea how to do it, but I don't like more code than I need and wanted to see if there was a easy simple solutions

here is the range code
@echo off

set /p range=IP Range: 
echo %range%|findstr /C:"-" >nul
if not errorlevel 1 (
 for /f "tokens=1-5 delims=.-" %%a in ("%Range%") do (
	set Oct1=%%a
	set Oct2=%%b
	set Oct3=%%c
	set Range1=%%d
	set Range2=%%e
)
for /l %%f in (%Range1%,1,%Range2%) do echo %Oct1:~-3%.%Oct2:~-3%.%Oct3:~-3%.%%f
) else (
	echo not a range.
)

exit /b 0

Open in new window


here is the validate code
:validateIP newAP [returnVariable]
SETLOCAL
SET "VALID=1"
ECHO %~1^| FINDSTR /B /E /R "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >NUL
IF NOT ERRORLEVEL 1 FOR /F "tokens=1-4 delims=." %%a in ("%~1") DO (
	IF %%a GTR 0 IF %%a LSS 255 IF %%b LEQ 255 IF %%c LEQ 255 IF %%d GTR 0 IF %%d LEQ 254 SET "VALID=0"
)
	IF %VALID% == 1 ECHO %newAP% is an invalid IP Address && CMD /C "EXIT/B 0" && SET "addIP=" && GOTO addIP
	ENDLOCAL & (IF NOT "%~2"=="" SET "%~2=%VALID%") & CMD /C "EXIT/B 0") && GOTO :EOF

Open in new window

crp0499CEOAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

oBdACommented:
Something like this (this now allows spaces in the range or list for better readability)?
@echo off
setlocal

set /p range=IP Range or list: 
echo %range%| find.exe "-" >nul && goto CreateRange
echo %range%| find.exe "," >nul && goto CreateList

echo Neither a range nor a list.
goto :eof

:CreateRange
for /f "tokens=1-5 delims=.- " %%a in ("%Range%") do (
	set Oct1=%%a
	set Oct2=%%b
	set Oct3=%%c
	set Range1=%%d
	set Range2=%%e
)
for /l %%f in (%Range1%, 1, %Range2%) do echo %Oct1%.%Oct2%.%Oct3%.%%f
goto :eof

:CreateList
for /f "tokens=1-4* delims=., " %%a in ("%Range%") do (
	set Oct1=%%a
	set Oct2=%%b
	set Oct3=%%c
	set Oct4List=%%d,%%e
)
for %%a in (%Oct4List%) do echo %Oct1%.%Oct2%.%Oct3%.%%a
exit /b 0

Open in new window

Bill PrewIT / Software Engineering ConsultantCommented:
I've got some good thoughts on this (I hope), but tied up most of today so won't be able to put something together until tonight.

So are the following the type of input you want to handle?

10.10.10.1
10.10.10.1-100
10.10.10.1,12,15,20,100

Would you ever want to handle this?

10.10.10.1-10,20-30

Or this?

10.10.10.1,9.9.9.9,8.8.8.8

~bp
crp0499CEOAuthor Commented:
oBdA that's perfect but can you do what Bill asked about:

"10.10.10.1
 10.10.10.1-100
 10.10.10.1,12,15,20,100

 Would you ever want to handle this?

 10.10.10.1-10,20-30

 Or this?

 10.10.10.1,9.9.9.9,8.8.8.8"

or is that not possible?
because I did not even think of that
Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

oBdACommented:
Input format is now changed, in order to differentiate between single IPs and ranges.
When you want to start a range or list, enter the first 3 octets, then a space or a comma (or both), then add any number of ranges or single host addresses in any combination.
@echo off
setlocal

set Range=
echo Input format: {^<Full IP^> ^| ^<Base Network^> {^<Host^> ^| ^<FirstHost^>-^<LastHost^>}[, ...]} [, ...]
echo Example: 1.1.1.1 2.2.2 5,6,7,8 10-20, 25, 30-40 8.8.8.8
set /p Range=IP range or list: 
if not defined Range goto :eof

set Tail=%Range%
:SliceInput
for /f "tokens=1* delims=, " %%a in ("%Tail%") do (
	set Head=%%a
	set Tail=%%b
)
echo %Head%| findstr.exe /r "^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$" >nul
if not errorlevel 1 (
	REM *** Full IP found; write it and process the rest of the line.
	echo %Head%
	set BaseIP=
	if defined Tail (goto :SliceInput) else (goto Done)
)
echo %Head%| findstr.exe /r "^[0-9]*\.[0-9]*\.[0-9]*$" >nul
if not errorlevel 1 (
	REM *** Base IP found; remember it and process the range or list following.
	set BaseIP=%Head%
	if defined Tail (goto :SliceInput) else (goto Done)
)
if not defined BaseIP (
	echo '%Head%': range or list defined without BaseIP.
	exit /b 1
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Single last octet found.
	echo %BaseIP%.%Head%
	if defined Tail (goto :SliceInput) else (goto Done)
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*-[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Range found
	for /f "tokens=1,2 delims=-" %%a in ("%Head%") do (
		for /l %%i in (%%a, 1, %%b) do echo %BaseIP%.%%i
	)
	if defined Tail (goto :SliceInput) else (goto Done)
)
echo Unsupported input format: '%Head%'
exit /b 1

:Done

Open in new window

crp0499CEOAuthor Commented:
oDbA you are awesome!

So there is not a way to do like Bill showed where 1.1.1.1-10,12,15 because you know it's going to be habit to always add the fourth period when doing this.
oBdACommented:
Never mind, I had something else in mind when starting on this. This has the IP verification in it as well:
@echo off
setlocal

set Range=
echo Allowed input format: {^<IP^> [^<Host^> ^| ^<FirstHost^>-^<LastHost^>][, ...]} [, ...]
echo Example: 1.1.1.1 2.2.2.2 5,6,7,8,10-20,25,30-40 8.8.8.8
set /p Range=IP range or list: 
if not defined Range goto :eof

set Tail=%Range%
:SliceInput
for /f "tokens=1* delims=, " %%a in ("%Tail%") do (
	set Head=%%a
	set Tail=%%b
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Full IP found; write it and process the rest of the line.
	call :TestAndEchoIP %Head%
	for /f "tokens=1-3 delims=." %%a in ("%Head%") do (
		set Network=%%a.%%b.%%c
	)
	if defined Tail (goto :SliceInput) else (goto Done)
)
if not defined Network (
	echo '%Head%': range or list defined without Network.
	exit /b 1
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Single last octet found.
	call :TestAndEchoIP %Network%.%Head%
	if defined Tail (goto :SliceInput) else (goto Done)
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*-[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Range found
	for /f "tokens=1,2 delims=-" %%a in ("%Head%") do (
		for /l %%i in (%%a, 1, %%b) do call :TestAndEchoIP %Network%.%%i
	)
	if defined Tail (goto :SliceInput) else (goto Done)
)
echo Unsupported input format: '%Head%'
exit /b 1

:TestAndEchoIP <IP>
set IP=%1
set IPOK=True
for %%a in (%IP:.= %) do (if %%a gtr 255 (set IPOK=False))
if /i "%IPOK%"=="False" (
	echo Not a valid IP: '%IP%'
	exit /b 1
)
echo %IP%
goto :eof
:Done

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Bill PrewIT / Software Engineering ConsultantCommented:
A couple of thoughts.

I was going to write my own version of this, but I feel like oBdA has done a great job with his approach, while I might do it slightly differently, I think this is a great approach so I don't see the value of an alternate.  Nice job.

I would suggest changing the display of invalid IPs to this, I think it reads a little better seeing all the IPs down the left.  Just a thought.

     echo %IP% *** INVALID ***

Also, it doesn't handle IPs in this format: "1.1.1.1-10"

These would have to be done like this, which isn't ideal: "1.1.1.1,2-10"

I do like this code though, have to say it again, very clean and understandable.

~bp
crp0499CEOAuthor Commented:
Thanks again oBdA, great work as always.

Thanks for the input Bill
Bill PrewIT / Software Engineering ConsultantCommented:
Welcome all, glad you got such a solid solution to your need.

~bp
oBdACommented:
Just for the fun of it, based on Bill's input, this one supports 1.1.1.1-10 as well; furthermore, it complains if a start range is lower than than the end range.
@echo off
setlocal

echo Input format: {{^<IP^> ^| ^<IP^>-^<LastHost^>} [^<Host^> ^| ^<FirstHost^>-^<LastHost^>][, ...]} [, ...]
echo Both comma and space can be used to separate hosts or range lists.
echo Example: 1.1.1.1 2.2.2.2-5 7, 8, 10-20,25, 30-40 8.8.8.8-12
set Range=
set /p Range=IP range or list: 
if not defined Range goto :eof

set Tail=%Range%
:SliceInput
for /f "tokens=1* delims=, " %%a in ("%Tail%") do (
	set Head=%%a
	set Tail=%%b
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Full IP found: '1.1.1.1'; write it and process the rest of the line.
	call :TestAndEchoIP %Head%
	for /f "tokens=1-3 delims=." %%a in ("%Head%") do (
		set Network=%%a.%%b.%%c
	)
	if defined Tail (goto SliceInput) else (goto Done)
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*-[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Full IP with subsequent range found: '1.1.1.1-10';
	REM *** set the Network, then redefine Head with the supplied range, 
	REM *** and let the new head fall through the rest of the script.
	for /f "tokens=1-4 delims=." %%a in ("%Head%") do (
		set Network=%%a.%%b.%%c
		set Head=%%d
	)
)
REM *** If we arrive here, it's either a single host, a range, or something incorrect.
if not defined Network (
	echo ERROR: '%Head%': range or list defined without Network.
	exit /b 1
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Single last octet found: '1'.
	call :TestAndEchoIP %Network%.%Head%
	if defined Tail (goto SliceInput) else (goto Done)
)
echo %Head%| findstr.exe /r "^[0-9][0-9]*-[0-9][0-9]*$" >nul
if not errorlevel 1 (
	REM *** Range found: '1-9'
	for /f "tokens=1,2 delims=-" %%a in ("%Head%") do (
		if %%a gtr %%b (
			echo ERROR: Range start '%%a' is greater than the range end '%%b'.
			exit /b 1
		)
		for /l %%i in (%%a, 1, %%b) do call :TestAndEchoIP %Network%.%%i
	)
	if defined Tail (goto SliceInput) else (goto Done)
)
echo ERROR: Unsupported input format: '%Head%'
exit /b 1

:TestAndEchoIP <IP>
set IP=%1
set IPOK=True
for %%a in (%IP:.= %) do (if %%a gtr 255 (set IPOK=False))
if /i "%IPOK%"=="False" (
	echo ERROR: Not a valid IP: '%IP%'
	exit /b 1
)
echo %IP%
goto :eof
:Done

Open in new window

Bill PrewIT / Software Engineering ConsultantCommented:
:-)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Windows Batch

From novice to tech pro — start learning today.