Jason Ross wrote: > Hello. Hello,
> I'm having a bit of an issue with a script I'm working on. The goal is > to parse the output of the solaris `prtvtoc` command and do some things > based on it. I've got that part down, and am placing the bits I care > about into a hash which is best written (I think ... ) as : > > $partition-> {$property} = value > > You can see what I mean in the code below... > > Anyway, the issue I have is that I need to determine where there are > gaps between the first sector and last sector (on the entire disk, not > on a given partition). How do you determine which partitions to skip and which not to skip? > So, for example, using the sample data below, I want to return "2097415 > - 69078878" as available sectors. > > I think to do that I need to iterate through all the last sectors and > find out if ($current_lastsector + 1) is not present in the list of > first sectors .... > > I'm not sure what the 'best' way to do that is given the structure of > the hash (it having the $partition top level is throwing me off) ... and > > I'm not convinced putting the startsectors and endsectors into 2 arrays > and comparing via that method is a good way to do it (and even if it is, > I'm not sure how to do that either ... ) > > Any thoughts on the 'best' way to do this ? > > (Sample data and script are below, any other "optimizations" folks feel > like chiming in with are welcome also ;-) > > > Sample data > > [snip] > > Sample script > -------------------------------------------------------------------------- > #!/usr/bin/perl You should start your Perl programs with these two lines: use warnings; use strict; > use strict(); You are telling perl to load the 'strict' module and then you are telling the 'strict' module not to do anything (with the empty parentheses.) Why use the module if you don't want it to do anything? > sub get_vtoc($) { You really, really, *REALLY* shouldn't use "prototypes". If you want to check the arguments passed to your subroutine you should do something like this: @_ == 1 or die "Wrong number of arguments passed to get_vtoc().\n"; "Far More Than Everything You've Ever Wanted to Know about Prototypes in Perl" http://library.n0i.net/programming/perl/articles/fm_prototypes/ > my $disk = shift; > my %slices; > > open(IN, "< $disk") or die("$!\n"); > while(<IN>) { > # make all tabs and spaces a single space > $_ =~ s/\s+/ /g; > # strip all leading spaces > $_ =~ s/^\s+//g; You don't really need those two substitutions if you use split() correctly later on. > # if this is the bytes/sector line, split it > # and store the bytes per sector as $BPS > if($_ =~ /bytes\/sector/) { > our (undef, $BPS, undef) = split(/\s/, $_, 3); our() is lexically scoped just like my() and the only reason that this actually works is because strict is turned off and $BPS is a package variable. To make this work correctly with strict you have to declare $BPS outside of the while loop. If you use split correctly that could be written as: $BPS = ( split )[ 1 ]; Then you wouldn't need the substitutions at the beginning of the loop. However *I* would write it like this: if ( /(\d+)\s+bytes\/sector/ ) { $BPS = $1; } > } > > # skip the the line if it starts with an * or is partition 2 > next if(/^[\*|2]/); Your comment is incorrect, it should read "if it starts with an * or a | or is partition 2". Regular expression meta-characters are not special in a character class so you probably meant /^[*2]/. > # split the line into its componant parts > my($part, $tag, $flag, $fsector, > $sectcount, $lsector, $mount) = split(/\s/, $_); If you use split() with NO arguments then you won't need the two substitutions at the beginning of the loop. If you really want to include the arguments then use ' ' instead of /\s/ as the first argument. > # put the pieces into the slices hash > $slices{$part} = { > bps => "$BPS", > tag => "$tag", > flag => "$flag", > part => "$part", > fsector => "$fsector", > lsector => "$lsector", > sectcount => "$sectcount", > mount => "$mount" perldoc -q quoting Found in /usr/lib/perl5/5.8.6/pod/perlfaq4.pod What’s wrong with always quoting "$vars"? > }; > } > close(IN); > return \%slices; > } To summarize: sub get_vtoc { my $disk = shift; my %slices; my $BPS; open my $IN, '<', $disk or die "$disk: $!\n"; while ( <$IN> ) { # if this is the bytes/sector line, split it # and store the bytes per sector as $BPS if ( /(\d+)\s+bytes\/sector/ ) { $BPS = $1; } # skip the the line if it starts with an * or is partition 2 next if /^(?:\*|\s*2)/; # split the line into its componant parts my ( $part, $tag, $flag, $fsector, $sectcount, $lsector, $mount ) = split; # put the pieces into the slices hash $slices{ $part } = { bps => $BPS, tag => $tag, flag => $flag, part => $part, fsector => $fsector, lsector => $lsector, sectcount => $sectcount, mount => $mount, ); } return \%slices; } > sub process_drive($) { > my $disk = shift; > my $slices = get_vtoc("$disk"); > > while(my ($partition, $properties) = each(%{$slices})) { > print "Partition: $partition\n"; > while(my ($property, $value) = each(%{$properties})) { > print "Property: $property => $value\n"; > } > print "\n"; # just a pretty fire > } This appears to do what you want (although there may be a module that does this better): my @sec_range; for my $sectors ( map [ @{ $_ }{ 'fsector', 'lsector' } ], sort { $a->{ fsector } <=> $b->{ fsector } } values %$slices ) { if ( @sec_range && $sec_range[ -1 ][ 1 ] == $sectors->[ 0 ] - 1 ) { $sec_range[ -1 ][ 1 ] = $sectors->[ 1 ]; } else { push @sec_range, $sectors; } } print "Available sectors:\n"; print "\t0 - ", $sec_range[0][0]-1, "\n" if $sec_range[0][0]; print "\t", $sec_range[$_-1][1]+1, ' - ', $sec_range[$_][0]-1, "\n" for 1 .. $#sec_range; > } > > process_drive("./in"); John -- use Perl; program fulfillment -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] <http://learn.perl.org/> <http://learn.perl.org/first-response>