I just started teaching myself Perl a couple days ago, and am looking forward to what this will give me for my Linux administration skills. Any help on this will be appreciated.
I ran into a problem in writing a simple script for searching for an entry in a file, then erasing the entire line. I know this can be done with grep -v in the Linux command line, but I felt I needed the practice.
The problem I'm having is that the script works, but when it finds and erases a match, it ignores the next match. I've already shown this to a friend who said it's a "weird way" to go about it, but he doesn't work much with arrays. -
#!/usr/bin/perl
-
-
use strict;
-
use warnings;
-
-
open(INFILE, "test") or die "Can't open file.";
-
my @array = <INFILE>;
-
close(INFILE);
-
-
my $number_removed = 0;
-
my $loops = 0; #Used to tell splice() what part of the array to remove
-
-
foreach my $l (@array) {
-
if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
-
splice(@array, $loops, 1); #Remove the part of the array that's
-
$number_removed += 1; #being searched
-
}
-
$loops += 1; #Each time a line is searched increment this value to
-
} #...allow splice to remove the correct line
-
-
open(OUTFILE, ">test_result"); #Print the remaining @array to a file
-
print OUTFILE @array;
-
close(OUTFILE);
-
-
print "$number_removed entries were removed.\n"
-
5 1869 miller 1,089
Recognized Expert Top Contributor
Greetings and welcome to perl.
Yes, your method of implementation is more difficult than it needs to be, but this will make for good practice. The main bug with your current implementation is the fact that you should not be incrementing the index when you remove an element from the array, becuase you just reduced the size by one. So here is your current code so fixed: -
#!/usr/bin/perl
-
-
use strict;
-
use warnings;
-
-
open(INFILE, "test") or die "Can't open test: $!";
-
my @array = <INFILE>;
-
close(INFILE);
-
-
my $number_removed = 0;
-
my $index = 0; #Used to tell splice() what part of the array to remove
-
-
foreach my $l (@array) {
-
if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
-
splice(@array, $index, 1); #Remove the part of the array that's
-
$number_removed++; #being searched
-
} else {
-
$index++; #Each time a line is searched increment this value to
-
}
-
} #...allow splice to remove the correct line
-
-
# Print the remaining @array to a file
-
open(OUTFILE, ">test_result") or die "Can't open test_result: $!";
-
print OUTFILE @array;
-
close(OUTFILE);
-
-
print "$number_removed entries were removed.\n"
-
However, there are two methods for file manipulation that you should probably learn for this. First of all, your entire loop procedure could be simplified by the use of the grep perl function. -
#!/usr/bin/perl
-
-
use strict;
-
use warnings;
-
-
open(INFILE, "test") or die "Can't open test: $!";
-
my @array = <INFILE>;
-
close(INFILE);
-
-
my $oldsize = @array;
-
-
# Remove all noted lines.
-
@array = grep {!/SHOREWALL/i} @array;
-
-
my $number_removed = $oldsize - @array;
-
-
# Print the remaining @array to a file
-
open(OUTFILE, ">test_result") or die "Can't open test_result: $!";
-
print OUTFILE @array;
-
close(OUTFILE);
-
-
print "$number_removed entries were removed.\n"
-
Also, you can take advantage of the Tie::File core module in order to simply edit the file in place. The use of your for loop and use of splice then comes in handy in a real way. -
#!/usr/bin/perl
-
-
use Tie::File;
-
-
use strict;
-
use warnings;
-
-
tie my @array, 'Tie::File', "test" or die "Can't open test: $!";
-
-
my $number_removed = 0;
-
-
for (my $index = 0; $index <= $#array;) {
-
if ($array[$index] =~ /SHOREWALL/i) {
-
splice @array, $index, 1;
-
$number_removed++;
-
} else {
-
$index++;
-
}
-
}
-
-
untie @array;
-
Also, as a general rule, whenever you find that you're keeping track of the index of an array, then you should use a for statement instead of a foreach. If you're just accessing the elements, then foreach is the way to go.
There are other methods to accomplish what you're trying to do, but these are two good ones to get you started on your quest for more tools.
- Miller
Miller, thank you very much for your corrections and suggestions. I will look at this closely and see what I can learn from it, and will use these techniques in more practice programs.
miller 1,089
Recognized Expert Top Contributor
Your welcome. Good luck.
- Miller
Miller, while I am sure your suggestion will be of great use, the corrected code you gave me still has the same symptom of skipping entries in the file. I created a new pl script and pasted the contents from your post.
In your response, you said that I shouldn't be incrementing the index, but does not your code do this as well? I don't suppose you have any other thoughts on this matter?
These are the contents of the file "test" that I used, with most lines numbered that helped me see what was going wrong.
SHOREWALL rocks
SHOREWALL SUCKS
George
Steve
3
4SHOREWALL
5SHOREWALL
6
7SHOREWALL
8SHOREWALL
9SHOREWALL
10
11SHOREWALL
12SHOREWALL
13SHOREWALL
14SHOREWALL
15
16SHOREWALL
17hi there bob
18SHOREWALL
19SHOREWALL
20hi
21there
22SHOREWALL
23bob
24go
25 away
26SHOREWALL
27i
28do
29not
30like
31mysteries
32
-Sean
miller 1,089
Recognized Expert Top Contributor
Greetings Sean,
You're right. The first code that I gave you doesn't work. The question is, can you figure out why? I know why, but the best way for you to learn would be to work through the steps. Let's see if I can help you:
Try adding some debugging statements to the script and see what results. Something like this is rather illuminating. It outputs the current -
foreach my $l (@arraymirror) {
-
print "$index - $l";
-
if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
-
splice(@array, $index, 1); #Remove the part of the array that's
-
$number_removed++; #being searched
-
print " Removed\n";
-
} else {
-
$index++; #Each time a line is searched increment this value to
-
}
-
} #...allow splice to remove the correct line
-
After viewing the output we see that some of the entries in the @array are being skipped. Immediately we ask why this is? I think we can presume that it has something to do with the fact that we are modifying the array that we are looping on. We could check perdoc for answers about foreach. However, it's try something else. How about just replacing the array that we're looping on with a duplicate array. -
my @staticarray = @array;
-
foreach my $l (@staticarray) {
-
print "$index - $l";
-
if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
-
splice(@array, $index, 1); #Remove the part of the array that's
-
$number_removed++; #being searched
-
print " Removed\n";
-
} else {
-
$index++; #Each time a line is searched increment this value to
-
}
-
} #...allow splice to remove the correct line
-
Ta-da! It works. Now obviously this is rather annoying. So now I go back to my earlier advice that I gave you. The other two methods of implementation do in fact work, and it's the third one that you should take note of. I told you that if you're ever accessing the index of an array, then you should just loop through the array by index instead of using foreach. The exact code that I provided that will can be used and will work. That gives us this -
use strict;
-
use warnings;
-
-
open(INFILE, "test") or die "Can't open test: $!";
-
my @array = <INFILE>;
-
close(INFILE);
-
-
my $number_removed = 0;
-
-
for (my $index = 0; $index <= $#array;) {
-
if ($array[$index] =~ /SHOREWALL/i) {
-
splice @array, $index, 1;
-
$number_removed++;
-
} else {
-
$index++;
-
}
-
}
-
-
# Print the remaining @array to a file
-
open(OUTFILE, ">test_result") or die "Can't open test_result: $!";
-
print OUTFILE @array;
-
close(OUTFILE);
-
-
print "$number_removed entries were removed.\n"
-
Output: -
>perl scratch.pl
-
16 entries were removed.
-
Good luck in your further studies.
- Miller
Sign in to post your reply or Sign up for a free account.
Similar topics |
by: sam |
last post by:
I have a function writen in Perl that takes a name-value list (array) as
argument
and returns a name-value list (array).
My question is:
How to call this function from PHP and get the returned name-value list in
PHP variable?
Thanks.
|
by: Xah Lee |
last post by:
Just bumped into another irresponsibility in perl.
the crime in question this time is the module File::Basename.
Reproduction:
1. create a directory containing a file of this name: "cdrom.html".
2. "use File::Basename;", with the line:
($name,$path,$suffix) = fileparse($File::Find::name, ('.html',
'.m'));
|
by: surfunbear |
last post by:
I've read some posts on Perl versus Python and studied a bit of my
Python book.
I'm a software engineer, familiar with C++ objected oriented
development, but have been using Perl because it is great for pattern
matching, text processing, and automated testing. Our company is really
fixated on risk managnemt and the only way I can do enough testing
without working overtime (which some people have ended up doing) is by
automating my...
|
by: dohnut |
last post by:
Here's one for some bored problem solver :)
I ran across this earlier today and fixed it, but don't exactly know
why. (that usually only happens in C :)
I'm using Perl version 5.8.0 btw.
Ok, let's start here: I end up with an array that comes from a
fetchrow_array() call to MySQL. I return the array to a function.
|
by: Vsevolod (Simon) Ilyushchenko |
last post by:
Hi,
I have succesfully connected from a dotnet client on Windows to a Perl
service and was able to send basic data types and arrays back to
Windows. However, I tried sending a two-dimensional array, and something
went wrong.
This is how I define the service in the client proxy:
| |
by: Kirt Loki Dankmyer |
last post by:
So, I download the latest "stable" tar for perl (5.8.7) and try to compile
it on the Solaris 8 (SPARC) box that I administrate. I try all sorts of
different switches, but I can't get it to compile. I need it to be
compiled with threads.
Anyone have any wisdom on how best to do this?
Here's a transcript of my latest attempt. It's long; you might want to
skip to the bottom, where I try "make" and the fatal errors start
happening.
|
by: KevinADC |
last post by:
Introduction
In part one we discussed the default sort function. In part two we will discuss more advanced techniques you can use to sort data. Some of the techniques might introduce unfamiliar methods or syntax to a less experienced perl coder. I will post links to online resources you can read if necessary. Experienced perl coders might find nothing new or useful contained in this article.
Short Review
In part one I showed you some...
|
by: pitjpz |
last post by:
We have moved our Database to another server. The server it was on used SQL 4 and the new one its on now uses SQL5
the only problem we can find is that when you attempt to delete a record from the DB the following happens:
When Deleting a record:
Fatal Error:
Can't call method "fetchrow_arrayref" on an undefined value at GT::SQL::File::delete_records line 275.
Stack Trace:
GT::Base (2704): main::fatal called at...
|
by: KevinADC |
last post by:
Note: You may skip to the end of the article if all you want is the perl code.
Introduction
Many websites have a form or a link you can use to download a file. You click a form button or click on a link and after a moment or two a file download dialog box pops-up in your web browser and prompts you for some instructions, such as “open” or “save“. I’m going to show you how to do that using a perl script.
What You Need
Any recent...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it.
First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed.
This is as boiled down as I can make it.
Here is my compilation command:
g++-12 -std=c++20 -Wnarrowing bit_field.cpp
Here is the code in...
| |
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth.
The Art of Business Website Design
Your website is...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own....
Now, this would greatly impact the work of software developers. The idea...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one.
At the time of converting from word file to html my equations which are in the word document file was convert into image.
Globals.ThisAddIn.Application.ActiveDocument.Select();...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols.
I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |