Link to home
Start Free TrialLog in
Avatar of crp0499
crp0499Flag for United States of America

asked on

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

Avatar of oBdA
oBdA

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

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
Avatar of crp0499

ASKER

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
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

Avatar of crp0499

ASKER

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.
ASKER CERTIFIED SOLUTION
Avatar of oBdA
oBdA

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
Avatar of crp0499

ASKER

Thanks again oBdA, great work as always.

Thanks for the input Bill
Welcome all, glad you got such a solid solution to your need.

~bp
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