Recently I was working on a script for log reporting. You know, one of those handy little guys that send you some info every day helping to make sure you keep up with whatever it is that you don’t want to forget about. Well, some of the data was in a plain old text file, and there is nothing wrong with that. It’s easy to simply cat the file and pipe it through mailx or mutt, no fuss, no muss.
But wait … this particular file is appended to when it is updated. What does that mean, you ask? That means that all the good stuff (recent entries) is at the bottom of the file. So, rather than sending the whole file every time, and then having to scroll past the same stuff over and over again, I used a quick couple of lines in my PERL script to take care of that for me.
First, let’s establish some info for the sake of this article. Let’s say the log file I am working with is in /tmp and is called mystuff.log, and we want to return 20 elements. The first thing I want to do in my script is to open the file and read in the contents. I can do this a couple ways, but I did this because it was quick and easy:
@mydata = `cat /tmp/mystuff.log`;
chop(@mydata);
@mydata_reversed = reverse(@mydata);
What this does, is uses the shell command cat, to put each line of the text file into an array. To be more PERL prudent, you could have done something like this:
open (MYSTUFF,"/tmp/mystuff.log") || die("Cannot open /tmp/mystuff.log");
@mydata = ;
Etc., etc., and so on. Either way works, just depends on what you are doing, what your preference is, what mood you are in. This was a quick and dirty script for my own use, so I made it easy on myself. If I were doing something professionally for a customer, I would have done things the “proper” way. The point I am trying to make is, that as you read this, bear in mind that there are many, many ways to go about the same thing. Especially in PERL.
In case anyone doesn’t know, the chop function is there to strip our the eol/carriage return from the end of each element in the array. Without that step, everything in the array would have an extra blank line after it which we don’t want. I’ll decide when and where to put extra blank lines thank you very much!
Next, you might notice the reverse function, which is really at the heart of this post. Basically, we get all of the data into an array, reverse it and then spit back out a set number of elements from the array. Since we reversed it, they will be the most recent entries!
“Why didn’t you just use sort -r from the command line since you were lazy and used cat anyway?” you ask?
Good question, and I am glad you brought that up. The reason I didn’t use the sort command (-r means reverse the output) is because I don’t want to sort the data, I want to simple reverse the order of the data, there is a difference. Besides, the data in the log file I was working with didn’t sort well anyway.
Since we have come this far, let’s take a look at the whole chunk of code based on earlier assumptions. This will open the specified log file, read all the lines into an array and reverse the order of those lines. It will then take the specified number of lines off the top (formerly the end) and put them into the specified output file. It should look something like this:
#!/usr/bin/perl
# This is the log file
$logfile = "/tmp/mystuff.log";
# This is the output file to hold the results
$outfile = "/tmp/myresults.txt";
# Setup the output file, open or create it while returning
# an error if it can't be opened or created.
open (LOGDATA,">$outfile") || die("Error opening $outfile\n");
print LOGDATA ("My Log Data\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
# Populate the array
@mydata = `cat $logfile`;
# Cut out the line breaks
chop(@mydata);
# Reverse the order
@mydata_reversed = reverse(@mydata);
# Grab some lines and print em out
for ($x=0;$x<=19;$x++) {
print LOGDATA ("$mydata_reversed[$x]\n");
}
# Close the file
close(LOGDATA);
There you go, it’s just that easy. Hopefully, you can see what I have done here and apply it to your own stuff. It’s not hard and it can come in pretty handy. Not just the reversing of files, but manipulating text files and other data that PERL is so good at. Enjoy!
Wouldn’t just be easier to use “tail -20 /tmp/mystuff.log” ?
Yes it would, if you just wanted the last 20 lines from a log file. In this case, even thought that’s what we ended up doing with the PERL code, the point was to illustrate how to do stuff using PERL so it could be used elsewhere for more complex things.