Version 23 of file exists

Updated 2011-07-03 10:40:58 by dkf
file exists name

Returns 1 if file name exists and the current user has search privileges for the directories leading to it, 0 otherwise.


Q. What's the difference between file exists and file isfile?

A. file exists returns true (1) for all existing directories and regular files. file isfile returns true only for existing regular files.


Note: if [file exists $a] && ([file type $a] == "file") then [file exists ${a}/], which seems inconsistent.

In normal usage, it wouldn't bother anyone, but in VFS work, there can be a world of difference between a file "$a", a directory "$a", and a file "$a/". I suspect this stems from [file split a/b] == {a b} != {a b {}} - 20040613 CMcC


MB : I have a problem on using the file exist command under windows XP while processing file names. The following script exhibits the problem. When one file "myfile.txt" is created, the file exist command says that the file "MYFILE.txt" exists, which is wrong since the two files have different name cases. I wonder if this is a portability problem because of the Windows XP platform or an internal bug of the Tcl command file exist.

  #
  # Test to know whether windows can take the case into account
  # in the file names
  #
  # 1. Create a new directory
  # 2. Create a new file in that directory
  # 3. Check that under windows the Tcl command "file exist" returns a wrong value.
  #
  package require fileutil
  set tmpdir [fileutil::tempdir]
  set newdir [file join $tmpdir "dirtotest"]
  file mkdir $newdir
  set filename [file join $newdir "myfile.txt"]
  puts "Touching $filename"
  fileutil::touch $filename
  set fexist [file exist $filename]
  puts "File exist : $fexist"
  set otherfilename [file join $newdir "MYFILE.txt"]
  puts "Other file : $otherfilename"
  set fexist [file exist $otherfilename]
  puts "Other file exist : $fexist"
  #
  # Check that the other file is not is the list returned by "glob"
  #
  set listOfFiles [glob -directory $newdir *]
  puts "Files : $listOfFiles"
  set found [lsearch $listOfFiles $filename]
  puts "Found $filename in the directory $newdir : $found"
  set found [lsearch $listOfFiles $otherfilename]
  puts "Found $otherfilename in the directory $newdir : $found"
  #
  # Clean-up
  #
  file delete -force $newdir

This script generates the output :

  Touching C:/WINDOWS/Temp/dirtotest/myfile.txt
  File exist : 1
  Other file : C:/WINDOWS/Temp/dirtotest/MYFILE.txt
  Other file exist : 1
  Files : C:/WINDOWS/Temp/dirtotest/myfile.txt
  Found C:/WINDOWS/Temp/dirtotest/myfile.txt in the directory C:/WINDOWS/Temp/dirtotest : 0
  Found C:/WINDOWS/Temp/dirtotest/MYFILE.txt in the directory C:/WINDOWS/Temp/dirtotest : -1

We can see that the returned value of the file exist command is wrong, and that the list returned by glob only shows the file "myfile.txt", which is the least ! I have not tested the same script under Linux, but it would be interesting. What is the explanation ? APN Not sure what discrepancy you are talking about. Windows file paths are not case sensitive so both myfile.txt and MYFILE.txt refer to the same file and file exists correctly returns 1 for both. Your lsearch is failing because the glob returns the file name as stored on disk when created (myfile.txt) and lsearch does case-sensitive matching and fails to match MYFILE.txt.


In June 2008, a comp.lang.tcl discussion arose regarding a user who was using file exists on symbolic links and who was frustrated when the results were not what was hoped for.

A poster provided

proc is_broken {linkname} {return [expr { ! [file exists [file readlink $linkname]] } ]

and then later in the program:

set rc [catch {is_broken $filename} result] 
    if {$rc == 0 && $result} { 
        puts "$filename is a broken link" 
    } elseif {$rc == 0} { 
        puts "link $filename is OK" 
    } else { 
        puts "$filename is not a link: $result" 
    } 

as code which could be used to test whether the symbolic link pointed to an existing file or not.