Jump to content

Need batch to create and read thru' Arrays.


Recommended Posts

I have .txt file with contents similar to below eg.

============================

Bus 1 Enclosure 1 Disk 12

Capacity: 274845

State: Unbound

Bus 1 Enclosure 1 Disk 13

Capacity: 274845

State: Unbound

Bus 1 Enclosure 2 Disk 0

Capacity: 274845

State: Enabled

Bus 1 Enclosure 2 Disk 1

Capacity: 274845

State: Enabled

Bus 2 Enclosure 3 Disk 0

Capacity: 1878379

State: Unbound

Bus 2 Enclosure 3 Disk 1

Capacity: 1878379

State: Enabled

Bus 2 Enclosure 3 Disk 2

Capacity: 1878379

State: Unbound

Bus 2 Enclosure 3 Disk 9

State: Empty

Bus 2 Enclosure 3 Disk 10

State: Empty

==================================

I need a batch file to do the below:

1. Read thru' the file and search only unbound disks and associated capacity.

2. Unique value of capacity and count of each value.

For eg.

The above data has two unique values of capacity for Unbound Disks -- '274845' & '1878379'.

Disk with capacity > 274845 has count 4 & disk with capacity > 1878379 has count 3

Note: I may be able to run .vbs as well, but prefer to have a .bat or .cmd

Thanks

Edited by Marcos
Link to comment
Share on other sites


Could you please provide a better explanation, it appears to me as if your count includes disks which are not Unbound.

Also it would help if you could provide an example of the output file you're expecting.

Link to comment
Share on other sites

Sorry, I seem to have confused self and others with my earlier statements. :}

I need the below:

1. No. of Unbound disks and their capacity.

2. No. of disks with similar capacity.

Output will be something like this for the above example.

No. of Unbound disks: 4

Count of Unbound disks with size 274845 = 2

Count of Unbound disks with size 1878379 = 2

Edited by Marcos
Link to comment
Share on other sites

This should do:

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
SET Unbound_274845=0
SET Unbound_1878379=0

FOR /F "tokens=1,2 delims=:" %%A IN ('TYPE "%~dpnx1"') DO (
IF "%%A"=="Capacity" SET /A Current=%%B
IF "%%B"==" Unbound" SET /A Unbound_!Current!+=1
)

SET /A Unbound=%Unbound_274845%+%Unbound_1878379%
ECHO No. of Unbound disks: %Unbound%
ECHO Count of Unbound disks with size 274845 = %Unbound_274845%
ECHO Count of Unbound disks with size 1878379 = %Unbound_1878379%

jaclaz

Link to comment
Share on other sites

I agree with Yzöwl.

Since batch scripts have no built in functions for creating or manipulating arrays we need to write them ourselves. The following tested script does what you ask, Marcos. In the following example the text file should be named "Disks.txt".

@ECHO OFF
SETLOCAL EnableDelayedExpansion

::Initialize array
SET "aCapacity="
SET "aUniqueCapacities="
SET /A nArrayDepth_Capacity=0
SET /A nArrayDepth_UniqueCapacities=0

::Create array of Unbound capacities
FOR /F "usebackq tokens=1-2" %%G IN ("Disks.txt") DO (
IF /I NOT "%%G %%H"=="State: Unbound" (SET sCapacity=%%H) ELSE (
SET "aCapacity=!aCapacity!!sCapacity! "
SET /A nArrayDepth_Capacity+=1
) )
ECHO No. of Unbound disks: !nArrayDepth_Capacity!

::Find unique capacity values (searching an array destroys the array, make a copy)
SET "aArrayToSearch=!aCapacity!"
FOR /L %%G IN (1,1,!nArrayDepth_Capacity!) DO (
FOR /F "tokens=1" %%H IN ("!aArrayToSearch!") DO (
IF !nArrayDepth_UniqueCapacities! EQU 0 (SET bElementSearch_FuncResult=False) ELSE (
CALL :Func_ElementSearch "%%H" "!aUniqueCapacities!" !nArrayDepth_UniqueCapacities!
)
IF /I "!bElementSearch_FuncResult!"=="False" (
SET "aUniqueCapacities=!aUniqueCapacities!%%H "
SET /A nArrayDepth_UniqueCapacities+=1
)
CALL :Func_FindStringLength "%%H"
SET /A nFindStringLength_FuncResult+=1
FOR /L %%I IN (1,1,!nFindStringLength_FuncResult!) DO (SET aArrayToSearch=!aArrayToSearch:~1!)
) )

::Count instances of unique capacity values
FOR /L %%G IN (1,1,!nArrayDepth_UniqueCapacities!) DO (
FOR /F "tokens=1" %%H IN ("!aUniqueCapacities!") DO (
CALL :Func_ElementSearch "%%H" "!aCapacity!" !nArrayDepth_Capacity!
ECHO Count of Unbound disks with size %%H = !nElementSearch_FuncResult!
CALL :Func_FindStringLength "%%H"
SET /A nFindStringLength_FuncResult+=1
FOR /L %%I IN (1,1,!nFindStringLength_FuncResult!) DO (SET aUniqueCapacities=!aUniqueCapacities:~1!)
) )
PAUSE
GOTO :eof

:Func_FindStringLength
:: %1=String of unknown length
SET sTestString_FindStringLength=%~1
SET /A nFindStringLength_FuncResult=0
:StringLengthUnknown_FindStringLength
IF NOT "!sTestString_FindStringLength!"=="" (
SET sTestString_FindStringLength=!sTestString_FindStringLength:~1!
SET /A nFindStringLength_FuncResult+=1
GOTO :StringLengthUnknown_FindStringLength
)
GOTO :eof

:Func_ElementSearch
:: %1=Element to find, %2=String array, %3=Depth of array
SET "aStringArray_ElementSearch=%~2"
SET "bElementSearch_FuncResult=False"
SET /A nElementSearch_FuncResult=0
FOR /L %%Q IN (1,1,%3) DO (
FOR /F "tokens=1" %%R IN ("!aStringArray_ElementSearch!") DO (
IF "%%R"=="%~1" (
SET bElementSearch_FuncResult=True
SET /A nElementSearch_FuncResult+=1
)
CALL :Func_FindStringLength "%%R"
SET /A nFindStringLength_FuncResult+=1
FOR /L %%S IN (1,1,!nFindStringLength_FuncResult!) DO (SET aStringArray_ElementSearch=!aStringArray_ElementSearch:~1!)
) )
GOTO :eof

Edited by 5eraph
Link to comment
Share on other sites

I'm not sure that the intention was to have pre-known the disk capacities.

Neither am I. :ph34r:

The posted example was the simplest possible covering OP requests as they were explicited (or at least as I understood them).

If you have n different disk sizes, the example can be easily made "self-learning".

New example:

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION

FOR /F "tokens=1,2 delims=:" %%A IN ('TYPE "%~dpnx1"') DO (
IF "%%A"=="Capacity" SET /A Current=%%B
IF "%%B"==" Unbound" SET /A Unbound_!Current!+=1
)

FOR /F "tokens=2 delims==" %%A IN ('SET Unbound_') DO SET /A Unbound_=!Unbound_!+%%A

ECHO No. of Unbound disks: %Unbound_%

FOR /F "Skip=1 tokens=1,2,3 delims=_=" %%A IN ('SET Unbound_') DO ECHO Count of Unbound disks with size %%B = !Unbound_%%B!

The batch does not check existance of any previous "Unbound_*" variable in the environment, but this can be added as a "safety/sanity" check.

SET Unbound_=
FOR /F "tokens=2 delims=_=" %%A IN ('SET Unbound_') DO SET Unbound_%%A=

jaclaz

Link to comment
Share on other sites

I hadn't thought of using variables that way, jaclaz, and didn't know it could be done (setting a variable name using another variable). I mainly repurposed code I've been working with recently.

Link to comment
Share on other sites

I hadn't thought of using variables that way, jaclaz, and didn't know it could be done (setting a variable name using another variable).

Yep :) that was supposed to be the clever part ;).

I mainly repurposed code I've been working with recently.

Yes, and definitely your snippet is a much better solution for "generic" arrays, but within the limits of OP needs, I find that the fun in the game is to find the simplest possible answer:

http://en.wikipedia.org/wiki/Occam's_razor

jaclaz

Link to comment
Share on other sites

Thanks a lot Guys !!!

Never knew it's such an AWESOME Forum !!!

Let me try the codes and see if it does the trick ! Will get back if I have any problems !

I suppose I can't 'challenge-enough' U guys with any 'This-is-too-hard-to-batch' problems :w00t: !

:thumbup

Edited by Marcos
Link to comment
Share on other sites

The command is typing the content of a given parameter, the parameter is intended to be your .txt file. drive:\path\name.extension

The following are two methods of running the batch file with the given parameter:

  • drag and drop the .txt file onto the batch file
  • enter the following into a command prompt X:\pathto\batchfile.cmd M:\pathto\textfile.txt

Alternatively replace:

FOR /F "tokens=1,2 delims=:" %%A IN ('TYPE "%~dpnx1"') DO (

with

FOR /F "usebackq tokens=1-2 delims=:" %%A IN ("M:\pathto\textfile.txt") DO (

Link to comment
Share on other sites

This one's for Jaclaz...

What does this do ('TYPE "%~dpnx1"') in the batch example ? Read from a file ? Do I need to replace something ?

:blushing: Sorry if it's a stupid question !

No, that is parameter %1 to the batch, normally the filename you wish to process.

Example:

You have saved the batch as countunbound.cmd and you have the list in a file that is called mylist.txt, this latter in C:\mylists\

You then invoke the batch like:

countunbound.cmd mylist.txt

provided that you open a command prompt in the same directory where BOTH files are (C:\mylists\).

Or:

C:\mybatches\countunbound.cmd mylist.txt

if the prompt is in the same directory where mylist.txt and it is not the same as the one countunbound.cmd is (C:\mybatches\)

Or:

countunbound.cmd C:\mylists\mylist.txt

if the prompt is in the directory where countunbound.cmd is and mylist.txt is in directory C:\mylists\.

"%~dpnx1"

will expand in all cases to "C:\mylists\mylist.txt"

see here also:

With this approach you should also be able to use drag 'n drop, just add a PAUSE at the end of the batch.

jaclaz

Link to comment
Share on other sites

I know that the question has been well and truly answered, but I had a few minutes to spare and decided to play around.

Here is the resulting script, it uses ideas from that which I've seen above.

@echo off & setlocal enableextensions enabledelayedexpansion
(set _t=m:\pathto\textfile.txt) & (set _s=unbound)
set "_u=!_s!_disks" & set "_z=!_u!_with_size" & set "!_u!=0"
for /f "delims=:" %%f in ('findstr/nil "!_s!" "%_t%"') do (
set "_=%%f" & set/a "!_u!+=1" & set/a "_-=1"
for /f "tokens=3 delims=: " %%c in (
'findstr/n .* "%_t%"^|findstr "^^!_!:"') do (
if not defined !_z!_%%c (set "!_z!_%%c=1") else (set/a "!_z!_%%c+=1"))
set "_=")
for /f %%a in ('set %_u%') do set "_=%%a" & echo=!_:_= !

The end user needs only to set the two variables on line two, i.e. the text file (M:\PathTo\TextFile.txt), the drive state (unbound | enabled)

Please bear in mind that this script is not intended as a better solution than what has gone before, it was done purely for the purpose of interest and because I'm back on a Windows PC today.

Link to comment
Share on other sites

And, at the ONLY scope of showing what the idea behind Occam's Razor is, I tried the various batches timing them on the sample file posted, which I saved as "unbound.txt".

Results (in a x10 loop):

  1. the second one posted by me (with "unbound.txt" hardcoded) takes around 30/100th in a x10 loop.
  2. the one by 5eraph is not working :ph34r: ( it just shows the total number of unbound disks, than hangs) @5eraph, can you check it? :blink: (maybe is one of those pesky copy/paste from board) updated, see below, it runs in around 80/100
  3. the one posted by Yzöwl takes around 1 seconds and 80/100 :w00t:
  4. the following one (in which I took the liberty of inverting the order of the output in order to remove a FOR loop) takes around 16/100th

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

FOR /F "tokens=1,2 delims=:" %%A IN (unbound.txt) DO (
IF "%%A"=="Capacity" SET /A Current=%%B
IF "%%B"==" Unbound" SET /A Unbound_!Current!+=1
)
FOR /F "tokens=1,2,3 delims=_=" %%A IN ('SET Unbound_') DO (
ECHO Count of Unbound disks with size %%B = !Unbound_%%B!
SET /A Unbound_=!Unbound_!+%%C
)

ECHO No. of Unbound disks: %Unbound_%

jaclaz

Edited by jaclaz
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...