How Can I Delete Just the Last Line of a Text File?

How Can I Delete Just the Last Line of a Text File?

  • Comments 8
  • Likes
Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I delete just the last line of a text file?

-- AD

SpacerHey, Scripting Guy! AnswerScript Center

Hey, AD. You know, it’s been a long, hard day here at Microsoft, one of those days when everyone and everything seems to be against you. Many people, when faced with a day like today, turn to the so-called comfort foods: meatloaf, beef stew, mashed potatoes and gravy, any food that’s familiar and reliable. When you’re a Scripting Guy faced with a day like today, you turn to the so-called comfort scripts: reading from and writing to text files. Familiar and reliable.

Note. Admittedly, we Scripting Guys would prefer to turn to comfort foods ourselves. However, we’re stuck with comfort scripts, at least until they start putting mashed potatoes and gravy into the vending machines around here.

It’s nowhere near as good as a meatloaf sandwich, but here’s a script that deletes just the last line of a text file:

Const ForReading = 1
Const ForWriting = 2

Set objFSo = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:\scripts\test.txt", ForReading)

strContents = objFile.ReadAll
objFile.Close

arrLines = Split(strContents, vbCrLf)

Set objFile = objFSO.OpenTextFile("c:\scripts\test.txt", ForWriting)

For i = 0 to UBound(arrLines) - 1
    objFile.WriteLine arrLines(i)
Next

objFile.Close

Actually, no, we hadn’t planned on explaining how the script works; when you order a meatloaf sandwich no one ever explains how that’s made, do they?

Oh, fine; we’ll see what we can do. We start out by defining a pair of constants, ForReading and ForWriting; we’ll use these constants to specify read-only or write-only mode when opening the text file. As usual, we need to open this file twice. In just a second we’re going to open the file for reading, and read in the existing contents. We’ll close the file, modify the contents in memory, then reopen the file and save the modified contents (that is, the old contents minus the very last line). It’s a bit of a hassle, but we have little choice here: the FileSystemObject won’t let us open a file for both reading and writing. Instead, at any given time we’re limited to doing one of those operations or the other.

And, yes, that is a bit like eating the mashed potatoes, and only then being able to eat the gravy, isn’t it?

After defining the two constants we create an instance of the Scripting.FileSystemObject and use the OpenTextFile method to open the file C:\Scripts\Testtxt. With the file open for reading we then use this line of code to read the entire text file and store the contents in a variable named strContents:

strContents = objFile.ReadAll

With the entire file stashed safely away in memory we then call the Close method to (temporarily) close the file.

Now what? As it turns out, our next step is to use the Split function to split the contents of the file into an array name arrLines, with each item in the array representing a line in the text file. We do that by splitting on the carriage return-linefeed character (or, as VBScript knows this character, vbCrLf):

arrLines = Split(strContents, vbCrLf)

Why do we do that? Well, the FileSystemObject doesn’t really know much about text files; for example, it doesn’t know which line is the last line in a given file. In that respect, arrays are a little smarter than the FileSystemObject. After all, any array can tell what its last item is: you can determine the last item in an array simply by calling the Ubound function, which returns the index number (subscript) of that item. For example, if the Ubound function returns a 13, then the last item in the array must have an index number of 13; in turn, that would mean thet we’re dealing with arrLines(13).

Hold on; we’re getting to that. So why is it useful to know that which item is the last item in the array? Well, we don’t want the last item to be included in our revised text file. If we know that the last item is item 13, then we know that our revised text file should only include items 0 through 12 (remember, the first item in an array is always item 0). We want to grab items 0 through 12 and then stop; that effectively deletes the last line in the text file.

Good idea: maybe we should just show you what we mean. After creating the array we reopen the text file, this time for writing; as you know, information we write to the file will completely replace the existing contents of the file. We then set up a For Next loop that runs from 0 to the Ubound value of the array minus 1:

For i = 0 to UBound(arrLines) - 1

Boy, you have a lot of questions today, don’t you? Why Ubound minus 1? Well, the Ubound function identifies the last item in the array. As we know, we don’t want the last item; however, we do want all the items up to – but not including – the last item. If the last item in the array is item 13, taking the Ubound value (13) and subtracting 1 leaves us with 12, which turns out to be the very value we need in our For Next loop. (To get items 0 through 12 our loop needs to run from 0 to, well, 12.) That’s why we use Ubound minus 1.

Inside our loop, and on the first go-round, we use the WriteLine method to write the value of array item 0 (the first item in the array, represented by the counter variable i) to the text file:

objFile.WriteLine arrLines(i)

We then loop around and repeat the process with the counter variable i equal to 1, meaning that we’ll write the value of array item 1 to the text file. This continues until we write the value of item 12 (the next-to-last item in the array) and then exit the loop. At that point we close the file and call it a day, without ever writing the last item in the array to the text file. We took a somewhat roundabout path here, but the net effect is that we’ve deleted the last line in the text file (simply by rewriting all the lines except the last line).

So will this really work? Of course it will. Suppose our text file looks like this, with the letter E being the actual last line of the file (that is, there’s no blank line following it):

A
B
C
D
E

What do you get back when you run the script? This:

A
B
C
D

Note. So what if your text file does have a blank line at the end? One thing you could do is check for that possibility – and remove the blank line – before you convert the text file to an array. Fortunately, we have a Hey, Scripting Guy! column that tells you how to do that very thing.

And that’s how the script works. As for the meatloaf sandwich, take two pieces of bread, put a little mustard on both pieces, and then slap a hunk of meatloaf in the middle. Feel free to use this recipe any time. Just make sure you credit the Scripting Guys.

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Lots of credit and many thanks for the script but the meatloaf recipe, hmmm I dont know, I'll pass.

  • The link to the previous column in the second last paragraph is  busted.  Contents are http://null/technet/scriptcenter/resources/qanda/may05/hey0520.mspx

    It should be

    blogs.technet.com/.../how-can-i-remove-the-last-carriage-return-linefeed-in-a-text-file.aspx

  • I have a two line text file. I implemented this script and the last line is printed instead of the first line.  Any ideas?

  • @Anthony thanks, I am glad you like the script.

    @Rob thanks for the update.

    @Grace, it is REALLY hard to troubleshoot a script sight unseen :-) I would suggest you post both your script, and your text file to the Official Scripting Guys Forum where there are many experts who would be glad to help you. The link is here: social.technet.microsoft.com/.../threads

  • No problem with last line being retained in this exact script but there is that old issue of disagreement over what constitutes the last line in a text file.

    If the original file ends with a blank line then the last line will not be removed.  The new file will also be created with the last line being blank.  The sum total is that the file will not be any different.  Remove the blank line and all will work well.

    Here is the ‘look-ahead’ method for removing the last line that will not see the blank line as a line.

    ##############################################

    Set fso = CreateObject("Scripting.FileSystemObject")

    Set infile = fso.OpenTextFile("ltest.txt")

    Set outfile = fso.OpenTextFile("ltest3.txt", 2,true) 'ForWriting, Create

    Do

       line = infile.ReadLine()

       if infile.AtEndOfStream Then Exit Do

       outfile.WriteLine line

    Loop While True

    infile.close

    outfile.Close

    ##############################################

    This is an interesting ‘race’ condition with the FSO that, as far as I know,  does not seem to arise in other implementations of the file API.

  • @JV You have hit upon a key problem in working with text files ... when there is a blank line at the end of the file, lots of things break. This is also an issue with many CSV type of files, and iterating through a collection ... often the last (blank line) will generate an error. The only way to ensure no blank line, is to go to the end of the text file, and backspace until your cursor appears at the end of the last line. I actually talk about this problem in the following Hey Scripting Guy blog article: blogs.technet.com/.../avoid-blank-lines-at-end-of-a-text-file-with-powershell.aspx

  • @Ed - I think the method I used here will always prevent that with VBScript.  LOading teh file into an array seems to always retain teh blank line.  When we write out all of the lines into the new file and close it without adding teh blank line the FSO just adds a new blank line.

    I believe that this is because the EOF marker is always acting like a new line.  If I backspace, remove the blank line then reopen the file, the blank line will always have returned.  If I load a file into an array in PowerSHell the pseudo-blank line will never be loaded.

    This has always been a headache in VBScript but almost nowhere else.

  • Hey Scripting Guy, How can I delete one letter in a string and retype the same letter that was deleted in the text file?? Please, Please Help !