我不是Tcl新手,这个问题困扰着我。我想遍历目录树,并处理或忽略那些我没有权限的子目录或文件。这是一个小样本代码:
#!/usr/bin/env tclsh
package require fileutil::traverse
proc errorHandler {absPath errorMessage} {
puts "ERROR: $absPath $errorMessage"
}
# Main
set searchDir /tmp
fileutil::traverse t $searchDir -errorcmd errorHandler
puts "\nFiles in $searchDir:"
t foreach fileName {
puts $fileName
}
输出:
...
couldn't read directory "/tmp/launchd-56801.nzZRsA/": permission denied
while executing
"glob -nocomplain -directory $current -types f -- *"
(procedure "GLOBF" line 2)
invoked from within
"GLOBF $top"
(procedure "::fileutil::traverse::Snit_methodnext" line 44)
invoked from within
"$self next currentfile"
(procedure "::fileutil::traverse::Snit_methodforeach" line 11)
invoked from within
"t foreach fileName {
puts $fileName
}"
(file "./traverser1.tcl" line 17)
我知道问题:我没有权限阅读某些子目录。这就是我为每个文档放入错误处理程序的原因。但是,从未调用该错误处理程序。我怀疑这是Tcl中的一个错误,但这可能意味着我误解了文档并且没有使用正确的包。我感谢任何帮助或建议来解决这个问题。
我查看了适用于Mac OS X 10.8.4 Moutain Lion和1.15版本的1.12版fileutil::traverse
的来源 - 最新版本。我找到的是:
method next {fvar} {
# code ...
if {![ACCESS $top]} {
Error ...
...
但对于Tcl 8.4或更高版本,ACCESS的实现是:
proc ::fileutil::traverse::ACCESS {args} {return 1}
而Tcl 8.3的实现是:
proc ::fileutil::traverse::ACCESS {current} {
if {[catch {
set h [pwd] ; cd $current ; cd $h
}]} {return 0}
return 1
}
当我用8.3版本替换8.4版本时,一切正常。这告诉我这是代码中的错误。我不知道为什么会这样。
答案 0 :(得分:2)
我通过添加预过滤器找到了解决方法,该过滤器尝试cd进入目录并在目录可访问时返回True:
#!/usr/bin/env tclsh
package require fileutil::traverse
# isAccessible: determines if the directory is accessible by attempting to cd into it
proc isAccessible {absPath} {
set currentDir [pwd]
if {[catch {cd $absPath}]} {
set chdirOK False
} else {
set chdirOK True
}
cd $currentDir
return $chdirOK
}
# Main
set searchDir /tmp
fileutil::traverse t $searchDir -prefilter isAccessible
puts "\nFiles in $searchDir:"
t foreach fileName {
puts $fileName
}
Donal的建议是一个伟大的建议:它有效,短而甜:
proc isAccessible {absPath} {
return [file readable $absPath]
}
我们甚至可以完全放弃isAccessible
:
fileutil::traverse t $searchDir -prefilter "file readable"