2009-01-09 20 views
10

Tengo un proc TCL principal que fuentes toneladas de otros procesos tcl en otras carpetas y subdirectorios posteriores. Por ejemplo, en el proc principal tiene:TCL: buscar recursivamente subdirectorios para obtener todos los archivos .tcl

source $basepath/folderA/1A.tcl 
source $basepath/folderA/2A.tcl 
source $basepath/folderA/3A.tcl 
source $basepath/folderB/1B.tcl 
source $basepath/folderB/2B.tcl 
source $basepath/folderB/3B.tcl 

y parece un poco estúpido hacerlo de esa manera cuando Siempre que voy a la fuente de todo en Foldera y FolderB. ¿Hay alguna función (o simple) que me permita obtener todos los archivos .tcl en una carpeta completa?

Respuesta

10

Basándose en la respuesta de Ramanman, aquí hay una rutina que aborda el problema utilizando los comandos de archivo TCL incorporados y que funciona en el árbol de directorios recursivamente.

# findFiles 
# basedir - the directory to start looking in 
# pattern - A pattern, as defined by the glob command, that the files must match 
proc findFiles { basedir pattern } { 

    # Fix the directory name, this ensures the directory name is in the 
    # native format for the platform and contains a final directory seperator 
    set basedir [string trimright [file join [file normalize $basedir] { }]] 
    set fileList {} 

    # Look in the current directory for matching files, -type {f r} 
    # means ony readable normal files are looked at, -nocomplain stops 
    # an error being thrown if the returned list is empty 
    foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] { 
     lappend fileList $fileName 
    } 

    # Now look for any sub direcories in the current directory 
    foreach dirName [glob -nocomplain -type {d r} -path $basedir *] { 
     # Recusively call the routine on the sub directory and append any 
     # new files to the results 
     set subDirList [findFiles $dirName $pattern] 
     if { [llength $subDirList] > 0 } { 
      foreach subDirFile $subDirList { 
       lappend fileList $subDirFile 
      } 
     } 
    } 
    return $fileList 
} 
+0

Gracias Jackson. ¡Creo que ahora podemos dejar todo esto en paz! – Lyndon

+3

Si tiene un enlace simbólico que crea un ciclo, obtendrá el error "demasiadas evaluaciones anidadas (bucle infinito?)". –

1

Aquí es una manera:

set includes [open "|find $basedir -name \*.tcl -print" r] 

while { [gets $includes include] >= 0 } { 
    source $include 
} 

close $includes 
+0

Gracias. Esto funcionó perfectamente. – Lyndon

5

quizás un poco más de la plataforma órdenes internas independientes y el uso de comandos en lugar de la tubería a un proceso:

foreach script [glob [file join $basepath folderA *.tcl]] { 
    source $script 
} 

Repetir para FolderB.

Si tiene criterios de selección más estrictos y no se preocupa de ejecutar en ninguna otra plataforma, el uso de find puede ser más flexible.

+0

Lo único que noté es que esto devuelve un error si no coinciden los archivos, pero es cierto que no revisé lo que hizo la otra respuesta. – Lyndon

+0

use la opción -nocomplain en el comando glob para detener el lanzamiento y el error si se genera una lista vacía. – Jackson

2

Basado en una respuesta anterior, esta versión se encarga de ciclos creados por los enlaces simbólicos y en el proceso elimina archivos duplicados debido a los enlaces simbólicos también.

# findFiles 
# basedir - the directory to start looking in 
# pattern - A pattern, as defined by the glob command, that the files must match 
proc findFiles {directory pattern} { 

    # Fix the directory name, this ensures the directory name is in the 
    # native format for the platform and contains a final directory seperator 
    set directory [string trimright [file join [file normalize $directory] { }]] 

    # Starting with the passed in directory, do a breadth first search for 
    # subdirectories. Avoid cycles by normalizing all file paths and checking 
    # for duplicates at each level. 

    set directories [list] 
    set parents $directory 
    while {[llength $parents] > 0} { 

     # Find all the children at the current level 
     set children [list] 
     foreach parent $parents { 
      set children [concat $children [glob -nocomplain -type {d r} -path $parent *]] 
     } 

     # Normalize the children 
     set length [llength $children] 
     for {set i 0} {$i < $length} {incr i} { 
      lset children $i [string trimright [file join [file normalize [lindex $children $i]] { }]] 
     } 

     # Make the list of children unique 
     set children [lsort -unique $children] 

     # Find the children that are not duplicates, use them for the next level 
     set parents [list] 
     foreach child $children { 
      if {[lsearch -sorted $directories $child] == -1} { 
       lappend parents $child 
      } 
     } 

     # Append the next level directories to the complete list 
     set directories [lsort -unique [concat $directories $parents]] 
    } 

    # Get all the files in the passed in directory and all its subdirectories 
    set result [list] 
    foreach directory $directories { 
     set result [concat $result [glob -nocomplain -type {f r} -path $directory -- $pattern]] 
    } 

    # Normalize the filenames 
    set length [llength $result] 
    for {set i 0} {$i < $length} {incr i} { 
     lset result $i [file normalize [lindex $result $i]] 
    } 

    # Return only unique filenames 
    return [lsort -unique $result] 
} 
9

Se vuelve trivial con tcllib a bordo:

package require fileutil 
foreach file [fileutil::findByPattern $basepath *.tcl] { 
    source $file 
} 
2

La misma idea que Schlenk:

package require Tclx 
for_recursive_glob scriptName $basepath *.tcl { 
    source $scriptName 
} 

si solo deseas Foldera y FolderB y no otras carpetas debajo de $ BasePath:

package require Tclx 
for_recursive_glob scriptName [list $basepath/folderA $basepath/folderB] *.tcl { 
    source $scriptName 
} 
0

La respuesta de Joseph Bui funciona bien, excepto que omite archivos en la carpeta inicial.

Cambio:

set directories [list]
Para:
set directories [list $directory]

para fijar

Cuestiones relacionadas