2009-01-09 16 views
10

Diğer klasörlerdeki ve diğer alt dizinlerdeki tonlarca diğer tcl proc'unu üreten ana bir TCL probu var.TCL: Tüm .tcl dosyalarının kaynağını oluşturmak için alt dizinleri ardışık olarak arayın

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 

ve ben her zaman FolderA ve folderB her şeyi kaynak olacak biliyorum zaman biraz aptalca bu şekilde yapmak gibi görünüyor: Örneğin, ana proc olduda. Tüm bir klasördeki tüm .tcl dosyalarını kaynamaya izin verecek bir işlev (veya basit yol) var mı?

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

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

close $includes 

cevap

10

Ramanman'ın yanıtını üzerine inşa etmek, yerleşik TCL dosya komutlarını kullanarak sorunu çözen ve dizin ağacında yinelemeli olarak çalışan bir rutin haline gelir. Bir önceki yanıt dayanarak

# 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

Teşekkürler Jackson. Sanırım hepsini dinlenmek için kullanabiliriz! – Lyndon

+3

Döngü yaratan sembolik bir bağınız varsa, "çok fazla iç içe geçmiş değerlendirme (sonsuz döngü?") Hatası alırsınız. –

1

İşte bir yoludur.

Daha sıkı seçim ölçütleriniz varsa ve başka platformlarda çalışma konusunda endişeleniyorsanız, bulma özelliğini kullanmak daha esnek olabilir.

+0

Teşekkür düzeltmek için. Bu mükemmel çalıştı. – Lyndon

5

Belki biraz daha platform bağımsız ve kullanan yerleşikleri bir işleme yerine boruların komutları: folderB için

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

tekrarlayın

+0

Fark ettiğim tek şey, herhangi bir dosya eşleşmezse bu bir hata döndürmesidir, ama kuşkusuz ki diğer cevabın ne yaptığını kontrol etmedim. – Lyndon

+0

, boş bir liste oluşturulduğunda atmayı ve hata vermeyi durdurmak için glob komutunda -komlakila seçeneğini kullanın. – Jackson

2

, bu sürüm de bağlı sembolik bağlantıları sembolik bağlantıların ve süreç çift dosyaları ortadan kaldırır oluşturulan döngüleri işler.

# 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

O gemide tcllib ile önemsiz alır:

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

Eğer sadece $ BasePath altında FolderA ve folderB değil başka klasörler isterseniz:: Schlenk'e olarak

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

aynı fikri

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

Joseph Bui'nin yanıtı, ilk klasördeki dosyaları atlaması dışında iyi çalışır.

Değişimi:

set directories [list]
için:
set directories [list $directory]