Hey, Scripting Guy! Question

Hey, Scripting Guy! I have a script that adds a line to a log file. Each time I add a new line to this file I would like to delete the last line in the file; that way I always have 20 lines in the file. Can you help me get this to work?
-- HW

SpacerHey, Scripting Guy! AnswerScript Center

Hey, HW. Well, today is Friday, June 6th, which means that the Scripting Guys have to get ready to head off for TechEd Orlando (where they’ll be delivering two showings of the classic instructor-led lab Windows PowerShell for VBScripters). As we speak the Scripting Editor is working at home; that way she can both edit this column and pack for the trip. Meanwhile, the Scripting Guy who writes this column is sitting at work writing this column. Why isn’t he home packing for the trip? That’s easy: he doesn’t need a lot of time to pack; instead, he has a system. Is he going to out of town for 4 days? No problem: right before he leaves he’ll grab the first four shirts hanging in his closet; grab whatever happens to be lying on top of this sock and underwear drawer; toss the whole mess into a suitcase; and head for the airport. Mission accomplished!

Note. Actually, that’s a little bit of an exaggeration. If he’s going out of town for an extended period of time, he might also fold the shirts; that makes it easier to cram them all into the suitcase. But now that we think about it, that’s about the only difference.

Anyway, the Scripting Guys are looking forward to returning to TechEd. After all, we have a lot of pleasant memories from TechEd 2007: riding Dudley Do-Right and Popeye and Bluto’s Bilge Rat Barges at Universal Islands of Adventure; eating chocolate-filled pastries every morning for breakfast; dining on Cuban sandwiches and hot apple crisp at Universal City Walk ….

Oh. And that conference thing, too.

Whatever it was.

At any rate, if you’re going to be at TechEd Orlando and you’re looking for an introduction to Windows PowerShell, well, feel free to drop by one of our labs. We’ll be doing one session at 10:00 AM Tuesday morning, then repeating that session at 1:00 PM Tuesday afternoon. We’ll have some nice handouts for everyone who attends; in addition, we sent the Scripting Editor down into the basement and she emerged with the last two boxes of Dr. Scripto bobblehead dolls. We’ll be giving away 12 bobbleheads in the morning session, and 12 more in the afternoon session.

Note. Can you attend both sessions, thus doubling your chances of winning a bobblehead? Sure; why not?

And what if you can’t make it to TechEd Orlando; what then? Well, fortunately we have a consolation prize for you. It might not sound like much, but it’s a script that can add a new line to a text file and, at the same time, remove the last line from that text file; in a recent poll many people said they would rather have a script like that than a trip to Florida.

Note. OK, it’s possible that we might be mistaken about that. But while we’re riding the water slides at Wet ‘n Wild we’ll be sure to ask people if they’d rather be riding the water slides at Wet ‘n Wild or reading about a script that can add a new line to a text file and, at the same time, remove the last line from that text file.

At any rate, enjoy:

Const ForReading = 1
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)

strText = Now & vbCrLf

strContents = objFile.ReadAll
arrContents = Split(strContents, vbCrlf)

If Ubound(arrContents) < 20 Then
    strText = strText & strContents
Else
    For i = 0 to 18
        strLine = arrContents(i)
        strText = strText & strLine & vbCrLf
    Next
End If

objFile.Close

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForWriting)
objFile.Write strText
objFile.Close

Before we launch into an explanation of the script and how it works, let’s take a look at the text file in question:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Pretty fancy, huh? Each time we run our script we want to insert a new line at the beginning of the file (for sample purposes we’re just going to enter the date and time); at the same time we need to delete the last line of the file. (That way our file always has 20 lines in it.) In other words, after we run the script the first time the text file should look something like this:

6/5/2008 10:43:08 AM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Nice; very nice. But how do we make this happen?

Well, to begin with, we define a pair of constants, ForReading and ForWriting; we’ll need these two constants in order to open and work with the txt file C:\Scripts\Test.txt. After defining the constants we create an instance of the Scripting.FileSystemObject, then use the following line of code to open Test.txt for reading:

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)

You can already feel the excitement beginning to build, can’t you?

After the text file is open we pause for a moment to assign the current date and time (using the VBScript function Now) and a carriage return-linefeed character (vbCrLf) to a variable named strText:

strText = Now & vbCrLf

As you might have guessed, this is the new value we’re going to add to the text file. (Of course, you really didn’t need to guess that; we mentioned earlier that we were going to add the current date and time to the file.) We then use the ReadAll method to read in the entire contents of the file and store that information in a variable named strContents:

strContents = objFile.ReadAll

Of course, we don’t really want to work with the text file contents as a whole; what we really want to work with are the individual lines in the file. (That way we can more easily insert a line at the beginning and chop off a line at the end.) Therefore, the next thing we do is use the Split function to split the contents of the file (the value of strContents) into an array:

arrContents = Split(strContents, vbCrlf)

By splitting on the carriage return-linefeed that turns arrContents into an array in which item represents an individual line in the text file.

And yes, that is kind of cool, isn’t it? Let’s just hope that the Nobel Prize Committee is paying attention.

You know what: we lied. Well, OK, it wasn’t really a lie, but we didn’t give you the entire picture. Just a second ago we said “…we don’t really want to work with the text file contents as a whole; what we really want to work with are the individual lines in the file.” That’s true, unless the text file has less than 20 lines in it. After all, suppose the text file has 1 line in it. If we add a new line at the beginning and then chop off the last line, well, how many lines will the text file have in it? That’s right: just 1. Not exactly what we want.

Note. By the way, good answer to the last question. Now try this one: Two trains leave Los Angeles 3 hours apart, headed for St. Louis. Train 1, which left at noon, travels at 50 miles an hour. Train 2, which left at 3:00 PM, travels at 65 miles an hour. Now, why would anyone want to take the train from Los Angeles to St. Louis?

Because of that, the next thing we do is check to see if the last item in the array arrContents (UBound) has an index number less than 20. If it does, then there’s no need to delete the last line in the text file; after all, we’re nowhere near the 20-line limit. That makes life easier; all we have to do is add the new value (strText) to the beginning of the file contents, like so:

strText = strText & strContents

We should probably mention that if your text file has no lines in it then you’re going to run into trouble here; that’s because attempting to read an empty text file results in an error. If there’s a chance you might have an empty file you might want to verify the size of the file before trying to read it; fortunately we have a script that shows you how to do just that. If the file is empty then you can simply write the new value to the file, without having to read from it.

But what if our text file already has 20 lines in it? (And what if it has more? No problem; by the time this script finishes running we’ll have trimmed it back down to the 20-line limit.) Well, if our text file already has 20 (or more) lines then we execute this block of code:

For i = 0 to 18
    strLine = arrContents(i)
    strText = strText & strLine & vbCrLf
Next

What are we doing here? To begin with, we’ve set up a For Next loop that runs from 0 to 18. Why? Well, we want to snag the first 19 lines in the text file; we don’t want anything to do with line 20 or any lines beyond that. Because the first item in an array has the index number 0, our loop needs to run from 0 to 18 rather than 1 to 19.

But you already knew that, didn’t you?

Inside the loop we use this line of code to grab the array item corresponding to the value of our counter variable i:

strLine = arrContents(i)

In other words, the first time through the loop i will be equal to 0; thus we’ll be grabbing the value of array item 0. And what is the value of array item 0? That’s right: it’s the first line in the text file.

Man, are you guys on a roll or what when it comes to answering questions today?

In line 2 we then tack this value (plus a carriage return-linefeed) onto the end of the variable strText. That’s going to make the first line in strText equal to the current date and time, and the second line equal to the first line in the text file. (See how that works? We’re essentially inserting a new line at the beginning of the file.) By the time we reach the end of the loop the 20th and last line in strText will be the 19th line in the text file.

Note. If you stop and visualize what we’re doing it should all be clear. Just imagine a space that can only hold 20 lines of text. When we insert a new line at the beginning that pushes all the other lines down one spot, and causes the 20th and last line to fall out of the space altogether.

At this point we’re almost done; all we have to do is close the file Test.txt, then immediately reopen it, this time for writing:

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForWriting)
objFile.Write strText
objFile.Close

Once the file has been reopened we use the Write method to replace the existing contents with the value of strText. We close the file one last time, and then call it a day, another job well done:

6/5/2008 10:43:08 AM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

That should do it, HW; at some point even the Scripting Guy who writes this column needs to get ready to head down to Florida. Let’s see, swimming suit; sunglasses; margarita glass; beach towel ….

Oh, yeah: and slides for the instructor-led lab. We were just about to mention those …. See you on Monday ... from Florida!