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

Hello,
I am trying to delete a scalar within array, but get the following error:
I am trying to search for an entry within the /etc/hosts file and then delete that scalar within the array after the match
Argument "1.1.1.1 hostname FQDN\n" isn't numeric in delete at ./hosts.pl
#!/usr/bin/perl -w open HOSTS, "/etc/hosts" or die "Cannot open hosts file! \n"; @hosts = <HOSTS>; foreach $line(@hosts) { if ($line =~ /($ARGV[0])/) { print $line; delete $hosts[$line]; } }
</code>

Replies are listed 'Best First'.
Re: deleting a non-numeric scalar within array
by GrandFather (Saint) on Dec 02, 2010 at 19:57 UTC

    If you know two slightly less well known things about Perl then you can:

    #!/usr/bin/perl use strict; use warnings; open my $hostsIn, '<', "/etc/hosts" or die "Cannot open hosts file! \n +"; my @hosts = <$hostsIn>; close $hostsIn; foreach my $line (@hosts) { next if $line !~ /($ARGV[0])/; print $line; $line = undef; }

    For that to make sense you need to know that delete sets an array element to undef (that is a lie, but it suffices at present - see the linked docs) and that the loop variable is an alias to the list elements being iterated over by a for loop.

    Note too the use of strictures (use strict; use warnings; - see The strictures, according to Seuss), lexical file handles and the three parameter open. Getting into the habit of using these techniques will save you a lot of time and frustration!

    True laziness is hard work
Re: deleting a non-numeric scalar within array
by jwkrahn (Abbot) on Dec 02, 2010 at 19:21 UTC

    $line contains a line of text from the file, you can't use that as an index into the array.    You need to do something like this:

    foreach my $index ( 0 .. $#hosts ) { if ( $hosts[ $index ] =~ /$ARGV[0]/ ) { print $hosts[ $index ]; delete $hosts[ $index ]; } }
Re: deleting a non-numeric scalar within array
by VinsWorldcom (Prior) on Dec 02, 2010 at 19:22 UTC

    You're printing $line - can't you see that it is not numeric and thus can't be used as an array index?

    One way is by changing the for loop (and some other modifications to improve your code):

    use strict; use warnings; open my $HOSTS, "<", "/etc/hosts" or die "Cannot open hosts file!\n"; my @hosts = <$HOSTS>; close $HOSTS; for my $line (0..$#hosts) { if ($hosts[$line] =~ /($ARGV[0])/) { print "$hosts[$line]"; delete $hosts[$line] } }
Re: deleting a non-numeric scalar within array
by locked_user sundialsvc4 (Abbot) on Dec 02, 2010 at 19:41 UTC

    Another sometimes-nifty trick is to use the grep function.   (There are several such functions, including map, that can save a rather large amount of time in certain cases.)

Re: deleting a non-numeric scalar within array
by Generoso (Prior) on Dec 02, 2010 at 21:16 UTC

    Have you tested tried the grep function and instead of looking for the ones to delete look for the ones to keep?

     @hosts = grep !/($ARGV[0])/,@hosts;
Re: deleting a non-numeric scalar within array
by jffry (Hermit) on Dec 02, 2010 at 21:51 UTC

    I agree with Generoso and sundialsvc4 on the use of grep. Although, I would use the BLOCK form of grep in keeping with PBP Chapter 8, "Always use a block with a map and grep." Like this:

    use strict; use warnings; open my $fh, '<', 'hosts' or die; my @hosts = <$fh>; close $fh; my @new_hosts = grep { !/$ARGV[0]/ } @hosts; print "\nnew_hosts:\n"; print join "", @new_hosts;

    However, this does not address your desire to print the excluded lines. For that, you could do this:

    use strict; use warnings; open my $fh, '<', 'hosts' or die; my @hosts = <$fh>; close $fh; print "Excluding these lines:\n"; my @new_hosts = grep { print $_ if /$ARGV[0]/; !/$ARGV[0]/} @hosts; print "\nThe new array:\n"; print join "", @new_hosts;

    But at that point, maybe your for loop might be clearer.

Re: deleting a non-numeric scalar within array
by poolpi (Hermit) on Dec 03, 2010 at 12:28 UTC

    You could do this with in-place edition:

    #perl -i.bak -pe 's/1\.1\.1\.1 hostname FQDN\n//g' /etc/hosts


    hth,
    PooLpi

    'Ebry haffa hoe hab im tik a bush'. Jamaican proverb