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. 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. ** See Also ** [Extral], by Peter De Rijk: Provides commands for handling temporary files. [fileutil]::tempfile and [fileutil::maketempir: Create temporary files and directories. [ycl%|%ycl dir autocreate]: Creates a temporary directory. [TIP #431 Discussion] has some discussion and code for createing temporary directories. ** Description ** 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 {$channl eq {}} { error [list {Failed to open a temporary file} $channel] } else { error [list {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