0

I have a script which generates a numbered file..

like this:

set no 0

file fn [open log_file_$no w]

I want to remember this no every time I run the script, i.e when running for the first time, the file name should be log_file_0 , 2nd time it should be log_file_1 etc.

Is there a way to "remember" the value of the variable so that it can be used later?

2
  • I'm not sure I understand what you are asking exactly. Could you perhaps give some more context? Commented Jun 23, 2014 at 11:18
  • I will be, more than once, running the script, thus generating the log_file everytime. I don't want to loose the previously generated files thus creating files with numbered names like shown above. Commented Jun 23, 2014 at 13:33

2 Answers 2

1

You need to store the value to disk somehow. Hoodiecrow gives you one sensible way to do it: in the actual filename. Other options:

  1. in a config file somewhere
  2. in a database (sqlite is good for this)

Demo for (1)

    # read the value
    if {[file exists num.dat]} {
        set fh [open num.dat r]
        set no [read -nonewline $fh]
        close $fh
    } else {
        set no 0
    }

    set logfile log_file_${no}

    # ...

    # write the value
    set fh [open num.dat w]
    puts $fh [incr no]
    close $fh

Demo for (2)

    package require Tcl 8.6
    package require tdbc::sqlite3

    set config_file config.db
    tdbc::sqlite3::connection create db $config_file

    # read the value
    if {[file exists $config_file]} {
        set stmt [$db prepare "create table config (number integer)"]
        $stmt execute
        $stmt close
        set no 0
    } else {
        set stmt [$db prepare "select number from config limit 1"]
        $stmt foreach row {
            set no [dict get $row number]
        }
        $stmt close
    }

    # ...

    # write the value
    set stmt [$db prepare "update config set number=:new limit 1"]
    $stmt execute [dict create new [incr no]]
    $stmt close

    $db close
Sign up to request clarification or add additional context in comments.

Comments

1

You don't need a variable, you have the number you need in the file list:

set no [scan [lindex [lsort -dictionary [glob log_file_*]] end] log_file_%2d]

incr no

set fn [open log_file_$no w]

Let's break that up a bit. Create a list of log files:

set filelist [glob log_file_*]

Sort the list in dictionary order (where 10 comes after 2) and pick the last element:

set highest_numbered [lindex [lsort -dictionary $filelist] end]]

Extract the number from the file name:

set no [scan $highest_numbered log_file_%2d]

Increase the number and open a new log file:

incr no
set fn [open log_file_$no w]

If there is a possibility that no log files exist, the glob command will fail. To take care of this case, either do this:

set filelist [glob -nocomplain log_file_*]
if {[llength $filelist]} {
    set highest_numbered [lindex [lsort -dictionary $filelist] end]]
    set no [scan $highest_numbered log_file_%2d]
} else {
    set no 0
}
incr no
set fn [open log_file_$no w]

or this slightly safer version (if you have Tcl 8.6):

try {
    glob log_file_*
} on ok filelist {
    set highest_numbered [lindex [lsort -dictionary $filelist] end]
    set no [scan $highest_numbered log_file_%2d]
} trap {TCL OPERATION GLOB NOMATCH} {} {
    set no 0
} on error message {
    puts stderr "error when listing log files: $message"
    set no -1
}
if {$no > -1} {
    incr no
    set fn [open log_file_$no w]
    # ...
    chan close $fn
}

Documentation: chan, glob, if, incr, lindex, lsort, open, scan, set, try

(Note: the 'Hoodiecrow' mentioned elsewhere is me, I used that nick earlier.)

4 Comments

This is not working. It shows the error:%Error opening flash:log_file_0 (File in use in an incompatible mode)can't read "log_file_": no such variable while executing "close $log_file_$no "
@aro Hmm, well, for the last one, you shouldn't have a $ before 'log'. For the first one, is another program/script/something else using the log file?
last error gone, i used close $fn but it now shows: no files matched glob pattern "log_file_*" while executing "glob log_file_*" invoked from within "set filelist [glob log_file_*]"
use glob -nocomplain ... to shush that error, then check the llength of the returned list. If it is empty, then set no 0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.