Recursion and exploring a file system

  1. In order to test a file system browser, we need a controlled file system to browse.

    The file mkdir command will create a new directory, just like the Windows/Dos and Unix/Linux mkdir command.

    Syntax: file mkdir path
    Creates a new directory.
    NOTE: The parent to the new directory must exist
    
    foreach path {tmp tmp/foo tmp/foo/bar} {
      file mkdir $path
    }
    

    The open command will open a file for read or write access

    Syntax: open fileName ?access?
    The open command is used to create a channel to a file, device, or to another program.
    open Open a file, device or pipe as a channel and return a handle to be used to access this channel.
    fileName The name of the file or device to open.
    ?access? How this file will be accessed by the channel. Values include r for read only mode, or w write only mode.

    Write a script that will create a set of folders under your current working directory. The folders should be tmp, tmp/tmp1, tmp/tmp2, and tmp/tmp3.

    Create 3 files in each folder -
    File Name Contents
    fileA-$folderName 12345
    fileB-$folderName 12345
    fileC-$folderName $folderName

    solution

  2. Processes that traverse a file system need to be careful to leave the application in a known state. If a procedure changes the state (for instance, the working directory) it may need to return the application to the previous state.

    Look at this code. It won't work.

    Each time listDirRecursively is invoked, it changes to a new folder. If this happens inside the foreach item loop, after the procedure returns, Tcl tries to process items that exist in the old folder while the working directory is the new folder.

    This bug can be fixed with a single new line of code to restore the working direcotry to the previous state after the procedure call. Fix the bug.

    
    proc listDirRecursively {dir} {
      cd $dir
      puts "CD TO: $dir FROM [pwd]"
      foreach item [glob -nocomplain *] {
      puts "Looking at $item in [pwd]"
        set type [file type $item]
        if {$type eq "directory"} {
          listDirRecursively $item
        } elseif {$type eq "file"} {
          puts "FILE: $item"
        }
      }
    }
    
    listDirRecursively tmp
    

    The output shouls start something like this:

    
    CD TO: tmp FROM /Volumes/Scratch/clif/tmp
    Looking at tmp1 in /Volumes/Scratch/clif/tmp
    CD TO: tmp1 FROM /Volumes/Scratch/clif/tmp/tmp1
    Looking at fileB in /Volumes/Scratch/clif/tmp/tmp1
    FILE: fileB
    Looking at fileC in /Volumes/Scratch/clif/tmp/tmp1
    FILE: fileC
    Looking at fileA in /Volumes/Scratch/clif/tmp/tmp1
    FILE: fileA
    Looking at fileB in /Volumes/Scratch/clif/tmp
    FILE: fileB
    Looking at tmp3 in /Volumes/Scratch/clif/tmp
    CD TO: tmp3 FROM /Volumes/Scratch/clif/tmp/tmp3
    

    If you don't see the third CD message, then you haven't fixed the bug.

    solution

  3. Another solution to traversing a file system is to use full paths, instead of relative paths for the glob commands, and never use the cd command.

    Rework the previous application to use complete paths instead of changing directories.

    Notice that the FILE message includes the complete path, while the previous version, that changed directories only has the file name.

  4. The file size command will return the number of bytes in a file.

    Modify the example from the lecture to use the file size command instead of md5 sums and report files that are the same size.

    Syntax: file size path
    Returns the size of the file in bytes.

    The output should look similar to this:

    
    These files are the same size (9 bytes): 
      /Volumes/Scratch/clif/tmp/tmp1/fileC
      /Volumes/Scratch/clif/tmp/tmp3/fileC
      /Volumes/Scratch/clif/tmp/tmp2/fileC
    These files are the same size (6 bytes): 
      /Volumes/Scratch/clif/tmp/tmp1/fileB
      /Volumes/Scratch/clif/tmp/tmp1/fileA
      /Volumes/Scratch/clif/tmp/fileB
      /Volumes/Scratch/clif/tmp/tmp3/fileB
      /Volumes/Scratch/clif/tmp/tmp3/fileA
      /Volumes/Scratch/clif/tmp/fileA
      /Volumes/Scratch/clif/tmp/tmp2/fileB
      /Volumes/Scratch/clif/tmp/tmp2/fileA
    


Copyright Clif Flynt 2010