TCL: متكرر الدلائل البحث إلى مصدر جميع الملفات .tcl
-
06-07-2019 - |
سؤال
ولدي بروك TCL الرئيسي الذي مصادر طن من procs 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
ويبدو نوع من الغباء أن تفعل ذلك بهذه الطريقة عندما أعرف دائما وسوف مصدر كل شيء في folderA وfolderB. هل هناك وظيفة (أو طريقة بسيطة) التي سوف اسمحوا لي أن مجرد مصدر جميع الملفات .tcl في مجلد كامل؟
المحلول
وبناء على رد ramanman، وهيريس الروتينية التي يعالج المشكلة باستخدام المدمج في الأوامر ملف TCL والذي يعمل هو الطريق شجرة الدليل بشكل متكرر.
# 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
}
نصائح أخرى
وويحصل تافهة مع tcllib على متن الطائرة:
package require fileutil
foreach file [fileutil::findByPattern $basepath *.tcl] {
source $file
}
وربما أكثر من ذلك بقليل منصة مستقلة واستخدام builtins الأوامر بدلا من الأنابيب إلى عملية:
foreach script [glob [file join $basepath folderA *.tcl]] {
source $script
}
وكرر لfolderB.
إذا كان لديك معايير اختيار أكثر صرامة، ولا تقلق حول تشغيل على أي منصات أخرى، وذلك باستخدام الاكتشاف قد يكون أكثر مرونة.
واستنادا إلى الإجابة السابقة، وهذه الصيغة يعالج دورات التي أنشأتها وصلات رمزية وعملية يزيل الملفات المكررة بسبب صلات رمزية أيضا.
# 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]
}
ونفس الفكرة كما schlenk:
package require Tclx
for_recursive_glob scriptName $basepath *.tcl {
source $scriptName
}
إذا كنت تريد فقط folderA وfolderB وليس مجلدات أخرى تحت $ basepath:
package require Tclx
for_recursive_glob scriptName [list $basepath/folderA $basepath/folderB] *.tcl {
source $scriptName
}
وهنا هي طريقة واحدة:
set includes [open "|find $basedir -name \*.tcl -print" r]
while { [gets $includes include] >= 0 } {
source $include
}
close $includes
والجواب من قبل جوزيف بوي يعمل بشكل جيد إلا أنه يتخطى الملفات في المجلد الأول.
والتغيير:
set directories [list]إلى:
set directories [list $directory]
ولإصلاح