user7145588
user7145588

Reputation: 37

how to write a tcl script to delete last line of a file

I have to delete the last line of file in using tcl script. I know the content so content replacement is also ok. But my content is which has to be replaced by a space or newline character or have to deleted. And my job is in a loop.

Please let me know which is the efficient way, capturing the entire file content each time in loop and replace that string is better or deleting simply the last line.

Please give some script code because I am very new to tcl.

Upvotes: 2

Views: 2829

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137557

Are we talking about removing the last line from the data on disk or the data in memory? It matters because the approach you use to do those two cases is entirely different.

In memory

Exactly how you manipulate things in memory depends on whether you're representing the data as list of lines or a big string. Both approaches work. (You could be doing something else too, I suppose, but these two are the common obvious ways.)

  1. If you've got your data as a list of lines in memory, you can simply do (assuming you're holding the lines in a variable called theLines):

    set theLines [lreplace $theLines end end]
    

    For a particularly large list, there are a few tricks to make it more efficient, but they come down to careful management of references:

    # Needs a new enough Tcl (8.5 or 8.6 IIRC)
    set theLines [lreplace $theLines[set theLines ""] end end]
    

    Try the first version instead of this if you don't know you need it. Also be aware that if you're wanting to keep the original list of lines around, you should definitely use the first approach.

  2. You might instead have the data in memory as a single big string. In that case, we can use some of Tcl's string searching capabilities to do the job.

    set index [string last "\n" $theString end-1]
    set theString [string range $theString 0 $index]
    

    The optimisation mentioned above in relation to lreplace is also applicable here (with all the same caveats):

    set index [string last "\n" $theString end-1]
    set theString [string range $theString[set theString ""] 0 $index]
    

On disk

When working on disk, things are different. There you need to be much more careful since you can't undo changes easily. There are two general approaches:

  1. Read the file into memory, do the change there (using the techniques above), and do a (destructive) ordinary write out. This is the approach you need when you are doing many other changes anyway (e.g., removing a line from the middle, adding a line to the middle, adding or removing characters from a line in the middle).

    set filename "..."
    
    # Open a file and read its lines into a list
    set f [open $filename]
    set theLines [split [read $f] "\n"]
    close $f
    
    # Transform (you should recognise this from above)
    set theLines [lreplace $theLines end end]
    
    # Write the file back out
    set f [open $filename "w"]
    puts -nonewline $f [join $theLines "\n"]
    close $f
    
  2. Find where the data you don't want starts as an offset in the file and truncate the file at that point. This is the right approach with a very large file, but it is rather more sophisticated.

    set f [open $filename "r+"];   # NEED the read-write mode!
    seek $f -1000 end;             # Move to a little bit before the end of the file.
                                   # Unnecessary, and guesswork, but can work  and will
                                   # speed things up for a big file very much
    
    # Find the length that we want the file to become. We do this by building a list of
    # offsets into the file. 
    set ptrList {}
    while {![eof $f]} {
        lappend ptrList [tell $f]
        gets $f
    }
    
    # The length we want is one step back from the end of the list
    set wantedLength [lindex $ptrList end-1]
    
    # Do the truncation!
    chan truncate $f $wantedLength
    close $f
    

However you do the disk transformations, make sure you test on a trash file before applying it to anything real! In particular, I've not checked what the truncation method does on a file without a newline at the end. It probably works, but you should test.

Upvotes: 1

Related Questions