deep27ak has asked for the wisdom of the Perl Monks concerning the following question:

Hello All,

I have an array as below (gets populated automatically and will vary on different machine)

192.169.32.0/255.255.255.0 192.169.72.0/255.255.255.0 192.169.73.0/255.255.255.0
and exports file
/file1 *(rw,sync,no_root_squash,no_subtree_check) /file2 *(ro,sync,no_root_squash,no_subtree_check) # shares for Tsp InstallServer file3 *(ro,sync,no_subtree_check)

Here I am not sure how can configure a subroutine to replace '*' with one subnet value each

like below
/file1 192.169.32.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file1 192.169.72.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file1 192.169.73.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file2 192.169.32.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) /file2 192.169.72.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) /file3 192.169.73.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) # shares for Tsp InstallServer file3 192.169.32.0/255.255.255.0(ro,sync,no_subtree_check) file3 192.169.72.0/255.255.255.0(ro,sync,no_subtree_check) file3 192.169.73.0/255.255.255.0(ro,sync,no_subtree_check)
I am trying few things
sub replace_exports { my $exports = 'exports'; open (EXPORTS,"<exports") ||die "Error opening exports file"; my @lines = <EXPORTS>; close (EXPORTS); my $lines; my @changes; foreach(@lines) { $_ =~ s/\*/@finalnwlist/g; push(@changes,$_); } open(EXPORTS, ">", $exports) || die "File not found"; print EXPORTS @changes; close(EXPORTS); } replace_exports ();

but this will just replace the '*' and dump the array but not what I want. Can someone help me here please.

Replies are listed 'Best First'.
Re: Replace an asterisk '*" with the content of array
by SimonPratt (Friar) on Sep 18, 2015 at 12:13 UTC

    Like this?

    use 5.16.2; my @finalnwlist = ( '192.169.32.0/255.255.255.0', '192.169.72.0/255.255.255.0', '192.169.73.0/255.255.255.0'); my @output = replace_exports(); use Data::Dumper; say Dumper \@output; sub replace_exports { chomp(my @lines = <DATA>); my @changes; foreach my $line (@lines) { foreach my $server (@finalnwlist) { my $output = $line; $output =~ s/\*/$server/g or next; push(@changes,$output); } } return @changes; } __DATA__ /file1 *(rw,sync,no_root_squash,no_subtree_check) /file2 *(ro,sync,no_root_squash,no_subtree_check) # shares for Tsp InstallServer file3 *(ro,sync,no_subtree_check)

      You're losing the comment line.

      use 5.16.2; my @finalnwlist = ( '192.169.32.0/255.255.255.0', '192.169.72.0/255.255.255.0', '192.169.73.0/255.255.255.0'); my @output = replace_exports(); use Data::Dumper; say Dumper \@output; sub replace_exports { chomp(my @lines = <DATA>); my @changes; foreach my $line (@lines) { if ($line !~ /\*/) { push(@changes,$line) } else { foreach my $server (@finalnwlist) { my $output = $line; $output =~ s/\*/$server/g; push(@changes,$output); } } } return @changes; } __DATA__ /file1 *(rw,sync,no_root_squash,no_subtree_check) /file2 *(ro,sync,no_root_squash,no_subtree_check) # shares for Tsp InstallServer file3 *(ro,sync,no_subtree_check)
      Dum Spiro Spero

        Yeah, I know :) I don't want to do everything for OP

Re: Replace an asterisk '*" with the content of array
by Anonymous Monk on Sep 18, 2015 at 10:32 UTC

    but this will just replace the '*' and dump the array but not what I want. Can someone help me here please.

    So what should it do instead?

    Start with this program

    #!/usr/bin/perl -- use strict; use warnings; my @finalnwlist = "192.169.32.0/255.255.255.0"; my @lines = "/file1 *(rw,sync,no_root_squash,no_subtree_check)"; foreach(@lines) { $_ =~ s/\*/@finalnwlist/g; print "$_\n"; }

      I cannot hardcode the @finalnwlist value as I said it will vary on different machine. This gets input from xml file.

      nor I can hardcode @lines with exports permission as you have done here.

      The script should check each line replace '*' with each of the subnet value and should do the same for all the subnets for all the shares

      The output should be like
      /file1 192.169.32.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file1 192.169.72.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file1 192.169.73.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file2 192.169.32.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) /file2 192.169.72.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) /file3 192.169.73.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) # shares for Tsp InstallServer file3 192.169.32.0/255.255.255.0(ro,sync,no_subtree_check) file3 192.169.72.0/255.255.255.0(ro,sync,no_subtree_check) file3 192.169.73.0/255.255.255.0(ro,sync,no_subtree_check)

        You need to identify the lines without * to let those pass through. Then loop over the network list but use a copy of the line in the substitution each time

        #!perl use strict; my @finalnwlist = qw( 192.169.32.0/255.255.255.0 192.169.72.0/255.255.255.0 192.169.73.0/255.255.255.0); replace_exports('exports.txt'); sub replace_exports { my $filename = shift; open IN,'<',$filename or die "Error opening $filename for read : $!"; my @lines = <IN>; close IN; open OUT, '>', 'chg_'.$filename or die "Error opening $filename for write : $!"; for (@lines) { chomp; if (m/\*/){ print "Change $_\n"; for my $nw (@finalnwlist){ my $copy = $_; $copy =~ s/\*/$nw/; print OUT $copy."\n"; } } else { print OUT $_."\n"; } } close OUT }
        poj

        I cannot hardcode the @finalnwlist value as I said it will vary on different machine. This gets input from xml file. nor I can hardcode @lines with exports permission as you have done here.

        You don't have to :)

        You're struck, and the key to getting unstuck

        Starting a new file, with minimal amount of code and minimal amount of hardcoded data like Re: Replace an asterisk '*" with the content of array

        Then simply explain what that program should do using as many words as you possibly can without copy/paste

        Please do this in the next minute and post what you get

Re: Replace an asterisk '*" with the content of array
by wee (Scribe) on Sep 23, 2015 at 23:22 UTC

    This might not be exactly what you're after, but I wrote it how I'd approach things. and I added more comments than I normally would in order to make it clear what direction I was after and explain things. It appears to do what you want.

    #!/usr/bin/perl use warnings; use strict; use FindBin qw($Bin); use Tie::File; # A list of IPs and subnet masks to substitute for '*' as we read thro +ugh a file of share info. If # you need this from a file, consider File::Slurp. my @ips = qw(192.169.32.0/255.255.255.0 192.169.72.0/255.255.255.0 192.169.73.0/255.255.255.0); # The path and name of the share file. my $sharefile = "$Bin/sharefile"; # Will hold the position in the @ips array as we progress through the +file looking for matches. my $last_index = '0'; # Holds the contents of the share file. my @contents; # This maps array elements to lines in the share file. tie(@contents, 'Tie::File', $sharefile) or die "Cannot tie $sharefile +: $!\n"; # Read each line in the file. If we see a '*' we replace it with an en +try in the @ips array. If a # replacement happens, we increment $last_index to point to the index +number of the next element in # the @ips array. If we matched the last element, we reset the counter + back to zero and start at # the beginning. for (my $i = 0; $i <= $#contents; $i++) { if ($contents[$i] =~ s/\*/$ips[$last_index]/) { if (++$last_index == @ips) { $last_index = '0'; } } } untie(@contents); print "Done editing $sharefile.\n";

    That assumes you have the share info in a file called 'sharefile' in the same directory as the script. After running, the sharefile file looks like this:

    /file1 192.169.32.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file1 192.169.72.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file1 192.169.73.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_ch +eck) /file2 192.169.32.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) /file2 192.169.72.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) /file2 192.169.73.0/255.255.255.0(ro,sync,no_root_squash,no_subtree_ch +eck) # shares for Tsp InstallServer file3 192.169.32.0/255.255.255.0/255.255.255.0(ro,sync,no_subtree_chec +k) file3 192.169.72.0/255.255.255.0/255.255.255.0(ro,sync,no_subtree_chec +k) file3 192.169.73.0/255.255.255.0/255.255.255.0(ro,sync,no_subtree_chec +k)

    I think that's what you were after anyway...

Re: Replace an asterisk '*" with the content of array
by locked_user sundialsvc4 (Abbot) on Sep 18, 2015 at 13:57 UTC

    One thing that I notice right away is that you are substituting $_ back into itself, instead of storing the result into a different my variable.   The first time you substitute-away the asterisk ... it is gone.