in tcl, how do I replace a line in a file?
Asked Answered
A

6

4

let's say I opened a file, then parsed it into lines. Then I use a loop:

foreach line $lines {}

inside the loop, for some lines, I want to replace them inside the file with different lines. Is it possible? Or do I have to write to another temporary file, then replace the files when I'm done?

e.g., if the file contained

AA
BB

and then I replace capital letters with lower case letters, I want the original file to contain

aa
bb

Thanks!

Argentous answered 12/5, 2010 at 11:3 Comment(0)
W
9

for plain text files, it's safest to move the original file to a "backup" name then rewrite it using the original filename:

Update: edited based on Donal's feedback

set timestamp [clock format [clock seconds] -format {%Y%m%d%H%M%S}]

set filename "filename.txt"
set temp     $filename.new.$timestamp
set backup   $filename.bak.$timestamp

set in  [open $filename r]
set out [open $temp     w]

# line-by-line, read the original file
while {[gets $in line] != -1} {
    #transform $line somehow
    set line [string tolower $line]

    # then write the transformed line
    puts $out $line
}

close $in
close $out

# move the new data to the proper filename
file link -hard $filename $backup
file rename -force $temp $filename 
Whither answered 12/5, 2010 at 14:50 Comment(4)
It's better to write to a file in the directory with a temporary name, then do a pair of file rename calls to first move the old file to backup and then the new file to the proper name. Or to use file link -hard to make the backup and file rename -force to move the temporary into place.Gwalior
The aim is to keep the old file with the old name for as long as possible. With the hardlink/replace approach, the replacement is atomic (rename() is an atomic POSIX operation) and there is always something with valid contents with the target name of the file. It's an old Unix hacker's trick. :-)Gwalior
@Donal, thanks for the info. It didn't occur to me (until I looked at the docs just now) that hard links were portable.Whither
@glennjackman, documentaion says "file link ?-linktype? linkName ?target?". You should switch the positions of $backup and $filename, to look like this "file link -hard $backup $filename".Grieco
A
6

In addition to Glenn's answer. If you would like to operate on the file on a whole contents basis and the file is not too large, then you can use fileutil::updateInPlace. Here is a code sample:

package require fileutil

proc processContents {fileContents} {
    # Search: AA, replace: aa
    return [string map {AA aa} $fileContents]
}

fileutil::updateInPlace data.txt processContents
Alpenhorn answered 14/5, 2010 at 20:12 Comment(0)
M
1

If this is Linux it'd be easier to exec "sed -i" and let it do the work for you.

Mulley answered 9/6, 2010 at 11:31 Comment(0)
M
0
set fileID [open "lineremove.txt" r] 
set temp [open "temp.txt" w+] 
while {[eof $fileID] != 1} { 
    gets $fileID lineInfo 
    regsub -all "delted information type here" $lineInfo "" lineInfo 
    puts $temp $lineInfo 
} 
file delete -force lineremove.txt 
file rename -force temp.txt lineremove.txt 
Maulstick answered 12/5, 2010 at 11:3 Comment(0)
S
0

If it's a short file you can just store it in a list:

set temp ""

#saves each line to an arg in a temp list
set file [open $loc]
foreach {i} [split [read $file] \n] {
    lappend temp $i
}
close $file

#rewrites your file
set file [open $loc w+]
foreach {i} $temp {
    #do something, for your example:
    puts $file [string tolower $i]
}
close $file
Sinful answered 10/6, 2010 at 20:47 Comment(0)
C
0

For the next poor soul that is looking for a SIMPLE tcl script to change all occurrences of one word to a new word, below script will read each line of myfile and change all red to blue then output the line to in a new file called mynewfile.

    set fin "myfile"
    set fout "mynewfile"

    set win  [open $fin  r]
    set wout [open $fout w]

    while {[gets $win line] != -1} {
       set line [regsub {(red)} $line blue] 
       puts $wout $line
    }

    close $win
    close $wout
Coppola answered 24/3, 2022 at 0:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.