Version 48 of file

Updated 2007-01-01 17:31:22

file - Manipulate file names and attributes

http://purl.org/tcl/home/man/tcl8.4/TclCmd/file.htm

file option name ?arg arg ...?

This command provides several operations on a file's name or attributes. Name is the name of a file; if it starts with a tilde, then tilde substitution is done before executing the command (see the manual entry for filename for details). Option indicates what to do with the file name. Any unique abbreviation for option is acceptable. The valid options are: (see complete man page; here's only notes on selected options).


file atime name ?time?

file attributes name

file attributes name ?option?

file attributes name ?option value option value...?

file channels ?pattern?

file copy ?-force? ?--? source target

file copy ?-force? ?--? source ?source ...? targetDir

file delete ?-force? ?--? pathname ?pathname ... ?

file dirname name

file executable name

file exists name

file extension name

file isdirectory name

file isfile name

file join name ?name ...?

file link ?-linktype? linkName ?target? (requires Tcl8.4)

file lstat name varName

file mkdir dir ?dir ...?

file mtime name ?time?

file nativename name

file normalize name (requires Tcl8.4)

file owned name

file pathtype name

file readable name

file readlink name

file rename ?-force? ?--? source target

file rename ?-force? ?--? source ?source ...? targetDir

file rootname name

file separator ?name?

file size name

file split name

file stat name varName

file system name (requires Tcl8.4)

file tail name

file type name

file volumes

file writable name


[Hopefully someone will provide some samples to show how these are useful. With the new VFS support in Tcl 8.4, and an appropriate extension, file can operate on much more than just local files (see the One-line web browser in Tcl for example).]


Can someone comment on what happens if the current working directory is on a different drive?

Yes. The question is essentially nonsensical because the current working directory is a per-drive attribute. What happens if I try to open the door, but the other door is open?

Hmm , so the following sequence, in Windows, is nonsense?

 cd C:/tcl/lib
 set fd [open "G:list.txt" "w"]
 set lst [glob *]
 puts $fd $lst
 close $fd

Interesting- I never realized that Windows was so brain-damaged.


LES: One may want to use this proc to catch a quick grasp of and/or memorize all the file commands:

 proc  fileinfo  { myFile }          {
        puts  "file name: $myFile"
        puts  "exists: [ file  exists  $myFile ]"
        puts  "----------------"
        puts  "type: [ file  type  $myFile ]"
        puts  "size: [ file  size  $myFile ]"
        puts  ""
        puts  "atime: [ file  atime  $myFile ]"
        puts  "mtime: [ file  mtime  $myFile ]"
        puts  ""
        puts  "pathtype: [ file  pathtype  $myFile ]"
        puts  "dirname: [ file  dirname  $myFile ]"
        puts  "separator: [ file  separator  $myFile ]"
        puts  "nativename: [ file  nativename  $myFile ]"
        puts  "normalize: [ file  normalize  $myFile ]"
        puts  "rootname: [ file  rootname  $myFile ]"
        puts  "tail: [ file  tail  $myFile ]"
        puts  "extension: [ file  extension  $myFile ]"
        puts  "join: [ file  join  $myFile ]"
        puts  ""
        puts  "attributes: [ file  attributes  $myFile ]"
        puts  "owned: [ file  owned  $myFile ]"
        puts  "readable: [ file  readable  $myFile ]"
        puts  "writable: [ file  writable  $myFile ]"
        puts  "executable: [ file  executable  $myFile ]"
        puts  ""
        puts  "channels: [ file  channels  $myFile ]"
        puts  "system: [ file  system  $myFile ]"
 }

run it: $ fileinfo somefile.txt

IL problems identifying what you're looking at? the following proc returns a simple string detailing what you have available to you. This is not great coding, but makes up for some TCL 8.3 ambiguities that might lead a programmer astray due to some assumptions. It also should rid you of the trailing slash problem.

 proc setloctype { loc { ambigtofile "false" } } {

    #   define a location as a directory or file or both.
    #   also identifies location as absolute or relative 
    #
    #   * manually choose to prefer files over directories when resolving ambiguous references if needed
    #
    #   examples:
    #       /mydirectory/name - absolute_dir
    #       logs/reports.log - relative_file_dir
    #       /restartfarms.sh - absolute_file

    set tailtype ""      

    if { [string range $loc end end] == "/" } {

        set tail ""
        set loc [string range $loc 0 end-1]
        set tailtype "dir"

    } else {

        set tail [file tail $loc]
        if { [regexp "\\." $loc] || [string is true $ambigtofile] } {
            set tailtype "file"
        } else {
            set tailtype "dir"        
        }
    }

    switch [file pathtype $loc] {

        "absolute" {
            switch [regexp -all "/" $loc] {
                "1" { 
                    if { $tailtype == "file" } {
                        set loctype "absolute_file" 
                    } else {
                        set loctype "absolute_dir"
                    }
                }
                default { 
                    if { $tailtype == "file" } {
                        set loctype "absolute_file_dir"
                    } else {
                        set loctype "absolute_dir"
                    }
                }
            }
        }

        "relative" - 
        default {
            switch [regexp -all "/" $loc] {
                "0" { 
                    if { $tailtype == "file" } {
                        set loctype "relative_file" 
                    } else {
                        set loctype "relative_dir"
                    }
                }
                default { 
                    if { $tailtype == "file" } {
                        set loctype "relative_file_dir" 
                    } else {
                        set loctype "relative_dir"
                    }                
                }
            }
        }
    }

    return $loctype
 }

JH I wanted to get a relative path based on another path and couldn't find a proc that did it, so here is one I made (with minimal testing):

 proc relpath {basedir target} {
     # Try and make a relative path to a target file/dir from base directory
     set bparts [file split [file normalize $basedir]]
     set tparts [file split [file normalize $target]]

     if {[lindex $bparts 0] eq [lindex $tparts 0]} {
         # If the first part doesn't match - there is no good relative path
         set blen [llength $bparts]
         set tlen [llength $tparts]
         for {set i 1} {$i < $blen && $i < $tlen} {incr i} {
             if {[lindex $bparts $i] ne [lindex $tparts $i]} { break }
         }
         set path [lrange $tparts $i end]
         for {} {$i < $blen} {incr i} {
             set path [linsert $path 0 ..]
         }
         return [eval [list file join] $path]
     }

     return $target
 }

 # Some examples
 relpath C:/Tcl/lib/tcllib C:/Tcl/lib/tcllib/module/pkgIndex.tcl
 # module/pkgIndex.tcl
 relpath [file dirname [info nameofexe]] [info library]
 # ../lib/tcl8.4
 relpath C:/Tcl/foo D:/Tcl/bar
 # D:/Tcl/bar
 relpath /usr/bin /usr/local/bin/tclsh
 # ../local/bin/tclsh

MG Edited so that it runs file normalize on both paths first - still works the same with all the examples above, but also handles, for instance

  cd "c:/program files/tcl/"
  relpath . [info library]
  # lib/tcl8.4

when one path is relative and one isn't. I was going to suggest

  return [join $path [file separator]]

instead of

  return [eval [list file join] $path]

to remove the eval, but for me (on Windows XP) that returns a different result - file separator returns a \, while file join joins using a /. Using

  return [file normalize [join $path [file separator]]]

would remove the need for eval and still return the same result as file join, I think. Is it intended that they (file separator and file join) use different characters on Windows? The docs for both say they use the "native character for the platform"...

JH The file join and file separator differences are intentional. Note that you can use file nativename to also get native again.


Csan How about a file mkfifo instead of exec mkfifo? Would be a lifesaver for us, un*x users...


See also:


Tcl syntax help - Arts and Crafts of Tcl-Tk Programming - Category Command - Category File - Additional file commands