There are two preferred, modern ways to make temporary files: 1. Tcl offered [file tempfile] for creating temporary files. 1. [Tcllib] provides commands for tempdir and tempfile within the http://core.tcl.tk/tcllib/doc/trunk/embedded/www/tcllib/files/modules/fileutil/fileutil.html%|%fileutil%|% package. However this page is dedicated to ways to create temporary files by adding a bit of Tcl code, for people who target distributions older than Tcl 8.6 (not having [file tempfile]) and do not wish to depend on tcllib. ---- The temp directory is put in to different environment variables on different systems. Examples are: Mac OS X: TMPDIR (tested on 10.8.5) Windows 2000: TMP and TEMP (tested on Windows 2000 SP3) CygWin: TMP and TEMP (tested on Cygwin 1.7.9) A scriptlet to do this: ====== set tmpdir [pwd] if {[file exists "/tmp"]} {set tmpdir "/tmp"} catch {set tmpdir $::env(TRASH_FOLDER)} ;# very old Macintosh. Mac OS X doesn't have this. catch {set tmpdir $::env(TMP)} catch {set tmpdir $::env(TEMP)} ====== If you just want one temp file: ====== set filename [file join $tmpdir [pid]] ====== If you want multiple tmpfiles, consider appending things like the application name, counter, time stamp, etc. For example: ====== set file [file join $tmpdir $appname.[pid].[incr ::globalCounter]] ====== ''DKF'' - Or create in a subdirectory/subfolder ====== if {![file exists [file join $tmpdir [pid]]]} { file mkdir [file join $tmpdir [pid]] } set file [file join $tmpdir [pid] [incr ::globalCounter]] ====== ''[Michael Schlenker]'' - Be aware of potential race conditions while opening temp files. The linux secure programming howto has some nice examples for the linux platform: http://en.tldp.org/HOWTO/Secure-Programs-HOWTO/avoid-race.html To be sure to get a new tempfile (and not some evil symlink) try something like: ====== set access [list RDWR CREAT EXCL TRUNC] set perm 0600 if {[catch {open $file $access $perm} fid ]} { # something went wrong error "Could not open tempfile." } # ok everything went well ====== ---- I had some luck with the following procedure on a UNIX box. Maybe, somebody can check if it works for windows. ====== proc tempfile {prefix suffix} { set chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" set nrand_chars 10 set maxtries 10 set access [list RDWR CREAT EXCL TRUNC] set permission 0600 set channel "" set checked_dir_writable 0 for {set i 0} {$i < $maxtries} {incr i} { set newname $prefix for {set j 0} {$j < $nrand_chars} {incr j} { append newname [string index $chars [expr {int(rand() * 62)}]] } append newname $suffix if {[file exists $newname]} { after 1 } else { if {[catch {open $newname $access $permission} channel]} { if {!$checked_dir_writable} { set dirname [file dirname $newname] if {![file writable $dirname]} { error "Directory $dirname is not writable" } set checked_dir_writable 1 } } else { # Success return [list $newname $channel] } } } if {[string compare $channel ""]} { error "Failed to open a temporary file: $channel" } else { error "Failed to find an unused temporary file name" } } ====== Igor Volobouev [AMG]: Here's a shorter version of the same: ====== proc tempfile {{filenameVar {}}} { set chars abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 if {$filenameVar ne {}} { upvar 1 $filenameVar filename } for {set i 0} {$i < 10} {incr i} { set filename /tmp/tcl_ for {set j 0} {$j < 10} {incr j} { append filename [string index $chars [expr {int(rand() * 62)}]] } if {![catch {open $filename {RDWR CREAT EXCL} 0600} channel]} { return $channel } } error "failed to find an unused temporary file name" } ====== [AMG]: And here's a variation which creates temporary directories: ====== proc temporaryDirectory {} { set chars abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 for {set i 0} {$i < 10} {incr i} { set path /tmp/tcl_ for {set j 0} {$j < 10} {incr j} { append path [string index $chars [expr {int(rand() * 62)}]] } if {![file exists $path]} { file mkdir $path file attributes $path -permissions 0700 return $path } } error "failed to find an unused temporary directory name" } ====== However, it is racy because Tcl does not provide a way to atomically check for a directory's existence, create it if it doesn't exist, and give it specified permissions. ---- [Stu] - My version of mkstemp(3) ====== proc randazAZchar {} { return [format %c [expr {int(rand() * 26) + [expr {int(rand() * 10) > 5 ? 97 : 65}]}]] } proc randazAZstring {length} { set s {} for {set i $length} {$i > 0} {incr i -1} {append s [randazAZchar]} return $s } proc makeTempFile {template} { if {[set xi [string first "X" $template]] == -1} { set n $template set p {} set rl 0 } else { set n [string range $template 0 [expr {$xi - 1}]] set p [pid] set rl [expr {[string length $template] - $xi - [string length $p]}] if {$rl < 0} { set p [string range $p 0 end-[expr {$rl * -1}]] set rl 0 } } for {set i [expr {int(pow(26, ($rl <= 6 ? $rl : 6)))}]} {$i > 0} {incr i -1} { set fn $n[randazAZstring $rl]$p if {![catch {open $fn {CREAT EXCL RDWR} 0600} fd]} { file delete $fn return $fd } if {[lindex $::errorCode 1] ne "EEXIST" || [lindex $::errorCode 0] ne "POSIX"} { break } } return -code error -errorcode $::errorCode $fd } ====== ---- wld Have a look at [GUID and UUID] for generating unique filenames for temp-files. ** Automatic disposal ** [dbohdan] 2015-04-26: I wrote the following procedure to manage temporary files in [tcltest] tests for [Sqawk]. It creates and opens temporary files, runs the code it was given and then automatically closes the files and deletes them. The design principle is the same as in [withOpenFile] and [with-path]. For Tcl 8.5 compatibility the procedure uses `::[fileutil]::tempfile` to generate filenames. ====== # Create and open temporary files (read/write), run a script then close and # delete the files. $args is a list of the format {fnVarName1 chVarName1 # fnVarName2 chVarName2 ... script}. proc with-temp-files args { set files {} set channels {} set script [lindex $args end] foreach {fnVarName chVarName} [lrange $args 0 end-1] { set filename [::fileutil::tempfile] uplevel 1 [list set $fnVarName $filename] lappend files $filename if {$chVarName ne ""} { set channel [open $filename w+] uplevel 1 [list set $chVarName $channel] lappend channels $channel } } uplevel 1 $script foreach channel $channels { catch { close $channel } } foreach filename $files { file delete $filename } } ====== <> Security | Tutorial | File