This is a relatively common request. Someone wants, for one reason or another, to determine how much diskspace is currently in use.

While on Unix one could say "exec /bin/du" , that doesn't do well for a cross platform solution.

Here's an attempt to provide some Tcl code to do this. However, I'm uncertain whether the calculation is correct. Perhaps some of my fellow Tcl'ers can look in here and determine whether my algorithm is correct.


 #! /usr/tcl84/bin/tclsh8.4
 # Name: du.tcl
 # Purpose: 
 # Given a directory, calcuate the number of bytes of plain files within
 # the directory
 # Author: [email protected]
 # Date: Sept. 26, 2002
 # Version: 1.0

 package require log 

 log::lvChannel debug stderr

 proc dirsize {directory} {
        if { [file exists $directory ] == 0 } {
                return 0
        }
        if { [file readable $directory ] == 0 } {
                return 0
        }
        set size 0
        set noaccess {}
        foreach element [glob -nocomplain -directory $directory -types f *] {
                set path [file join $directory $element]
                if { [file readable $path] } {
                        array unset stats
                        file stat $path stats
                        incr size $stats(size)
                } else {
                        lappend noaccess $path
                }
        }
        if { [llength $noaccess] != 0 } {
                log::log debug $noaccess
        }
        return $size
 }

 proc dir_totalsize {directory} {
        if { [file exists $directory ] == 0 } {
                return 0
        }
        if { [file readable $directory ] == 0 } {
                return 0
        }

        set size 0
        set noaccess {}
        foreach element [glob -nocomplain -directory $directory -types d *] {
                set path [file join $directory $element]
                if { [file readable $path] } {
                        incr size [dirsize $element]
                } else {
                        lappend noaccess $path
                }
        }
        if { [llength $noaccess] != 0 } {
                log::log debug $noaccess
        }
        return $size
 } 

 # Test out implementation

 if { [file exists /tmp/small] == 0 } {
        exec mkdir /tmp/small
        exec cp /etc/motd /tmp/small/motd
 }

 puts [format "Size of /tmp/small is %d" [dirsize /tmp/small] ]
 puts [format "Size of %s is %d" $env(HOME) [dirsize $env(HOME)] ]
 puts [format "Size of /not/present is %d" [dirsize /not/present] ]
 puts [format "Total size of %s is %d" $env(HOME) [dir_totalsize $env(HOME)] ]

Hmm... am I missing something? What's wrong with this??

 proc du { { dir . } } {
     if { ! [ file isdirectory $dir ] } {
        return [ file size $dir ]
     }

     set globpat $dir/*
     set bytes 0

     while { 1 } {
         set files [ glob -nocomplain $globpat ]
         if { ! [ llength $files ] } {
            break
         }
         set globpat [ list ]
         foreach file $files {
           # pesky links, dagnabbit!! 
           if { ! [ catch {
               file readlink $file
            } ] } {
               continue
            }
            if { [ file isdirectory $file ] } {
               lappend globpat $file/*
            } else {
               incr bytes [ file size $file ]
            }
         }
         if { ! [ llength $globpat ] } { break }
     }
     return $bytes
 } ;# -PSE

Hmmm... looks like a candidate for tcllib?

NO. but I got carried away, and suppose this is: du