Search code examples
tclwildcardglob

Wildcard Search with tcl glob


I am trying to search for directories within sub-directories and return any directories that match the wildcard glob search.

The folder structure is as outlined below...

Rootdir
 -dir01
   -dir_match_01-OLD
   -dir_match_01
 -dir02
   -dir_match_02-OLD
   -dir_match_02
 -dir03
   -dir_match_03-OLD
   -dir_match_03
 -...

I am searching for directories that would reside in dir01, dir02, dir03 and so on.

I am using the following glob call to recursively search through the directories, which seems to be working correctly...

set rootdir "/home/rootdir/"
set searchstring "*-OLD"

foreach dir [glob -nocomplain -dir $rootdir -type d -- *] {
  set result [glob -nocomplain -dir $dir -type d -- $searchstring]
  puts $result
}

What I am finding is if I don't use a wildcard in the $searchstring and use an exact directory name that exists I receive the output successfully. But if I then use a wildcard to search for all directories ending in *-OLD It successfully finds them put puts them all out on the same line.

/home/rootdir/dir01/directory01-OLD /home/rootdir/dir01/directory02-OLD /home/rootdir/dir01/directory03-OLD

I have tried to separate the entries by using regsub to replace the whitespace with \n but all it does is remove the whitespace...

/home/rootdir/dir01/directory01-OLD/home/rootdir/dir01/directory02-OLD/home/rootdir/dir01/directory03-OLD

Any suggestions in what I am doing wrong would be much appreciated, thanks.


Solution

  • The most obvious part is that glob always returns a list of names. You'd therefore need to do the innermost loop like this:

    foreach dir [glob -nocomplain -dir $rootdir -type d -- *] {
        foreach result [glob -nocomplain -dir $dir -type d -- $searchstring] {
            puts $result
        }
    }
    

    However, for a fixed depth search, I think you can do it like this:

    foreach dir [glob -nocomplain -dir $rootdir -type d -- */$searchstring] {
        puts $dir
    }
    

    If you need recursive (full directory tree) search, there are utility commands in Tcllib's fileutil package:

    package require fileutil
    
    proc myMatcher {pattern filename} {
        # Does the filename match the pattern, and is it a directory?
        expr {[string match $pattern $filename] && [file isdir $filename]}
    }
    
    set rootdir "/home/rootdir/"
    set searchstring "*-OLD"
    
    # Note the use of [list] to create a partial command application
    # This is a standard Tcl technique; it's one of the things that [list] is designed to do
    foreach dir [fileutil::find $rootdir [list myMatcher $searchstring]] {
        puts $dir
    }