в tcl, как мне заменить строку в файле?

допустим, я открыл файл, а затем разобрал его по строкам. Затем я использую цикл:

foreach line $lines {}

внутри цикла для некоторых строк я хочу заменить их внутри файла на другие строки. Является ли это возможным? Или мне нужно записать в другой временный файл, а затем заменить файлы, когда я закончу?

например, если файл содержал

AA
BB

а затем я заменяю заглавные буквы строчными буквами, я хочу, чтобы исходный файл содержал

aa
bb

Спасибо!


person n00b programmer    schedule 12.05.2010    source источник


Ответы (4)


для простых текстовых файлов безопаснее всего переместить исходный файл под "резервное" имя, а затем перезаписать его, используя исходное имя файла:

Обновление: отредактировано на основе отзыва Донала

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 
person glenn jackman    schedule 12.05.2010
comment
Лучше записать в файл в каталоге с временным именем, а затем выполнить пару вызовов file rename, чтобы сначала переместить старый файл в резервную копию, а затем новый файл с правильным именем. Или использовать file link -hard для создания резервной копии и file rename -force для перемещения временного файла на место. - person Donal Fellows; 13.05.2010
comment
Цель состоит в том, чтобы как можно дольше сохранить старый файл со старым именем. При подходе жесткой ссылки / замены замена является атомарной (rename() - это атомарная операция POSIX), и всегда есть что-то с допустимым содержимым с целевым именем файла. Это старый хакерский трюк Unix. :-) - person Donal Fellows; 13.05.2010
comment
@Donal, спасибо за информацию. Мне и в голову не приходило (пока я только что не посмотрел документацию), что жесткие ссылки переносимы. - person glenn jackman; 13.05.2010
comment
@glennjackman, в документе говорится, что ссылка на файл? -linktype? linkName? target ?. Вы должны поменять местами $ backup и $ filename, чтобы эта ссылка на файл выглядела как -hard $ backup $ filename. - person Vikyboss; 27.06.2015

В дополнение к ответу Гленна. Если вы хотите работать с файлом на основе всего содержимого и файл не слишком велик, вы можете использовать fileutil :: updateInPlace. Вот пример кода:

package require fileutil

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

fileutil::updateInPlace data.txt processContents
person Hai Vu    schedule 14.05.2010

Если это Linux, было бы проще выполнить команду "sed -i" и позволить ей сделать всю работу за вас.

person eemz    schedule 09.06.2010

Если это короткий файл, вы можете просто сохранить его в списке:

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
person Jack    schedule 10.06.2010