Tcl深度递归文件搜索,搜索扩展名为*.c的文件。

4

使用一个旧答案在tcl中搜索文件:

https://dev59.com/23RC5IYBdhLWcg3wCMnX#435094

首先让我们讨论我现在正在做什么:

使用以下函数:(感谢Jacson)

# 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
 }

同时执行以下命令:

findFiles some_dir_name *.c

当前结果:

bad option "normalize": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, lstat, mtime, mkdir, nativename, owned, pathtype, readable, readlink, rename, rootname, size, split, stat, tail, type, volumes, or writable

现在,如果我们运行以下命令:
glob *.c

我们收到了很多文件,但它们都在当前目录下。
我们的目标是获取机器上所有子文件夹中的所有文件及其路径。 有谁可以帮忙吗?
我真正想做的是找到包含最多*.c文件的目录。然而,如果我能列出所有文件和它们的路径,我就可以计算每个目录中有多少文件并得到其中包含最多文件的目录。

错误来自于一个过旧的Tcl版本,请尝试使用更新的Tcl,您至少需要Tcl 8.4(这只有10年历史...)。 - schlenk
如果我在目录名末尾加上空格(这在大多数系统上是合法的,但非常棘手!)那么代码就完全失败了!Bwahahaha!(不要对从“glob”中获取的内容进行“string trim”...) - Donal Fellows
3个回答

4

您正在使用旧版本的Tcl。[file normalize]是在2002年左右的Tcl 8.4中引入的。请升级到最新版本。

如果您无法升级 - 那么您可以使用glob,但仅为文件调用一次,然后遍历目录。请参见glob -types选项。

以下是一个演示:

proc on_visit {path} {
    puts $path
}

proc visit {base glob func} {
    foreach f [glob -nocomplain -types f -directory $base $glob] {
        if {[catch {eval $func [list [file join $base $f]]} err]} {
            puts stderr "error: $err"
        }
    }
    foreach d [glob -nocomplain -types d -directory $base *] {
        visit [file join $base $d] $glob $func
    }
}

proc main {base} {
    visit $base *.c [list on_visit]
}

main [lindex $argv 0]

这个很好用,你能否添加注释来帮助我(和其他人)理解代码? - AturSams

4
我会使用 ::fileutil::traverse 函数来完成它。
类似这样:

Something like:

package require ::fileutil::traverse

proc check_path {path} {
     string equal [file extension $path] ".c"
}

set obj [::fileutil::traverse %AUTO% -filter check_path]
array set pathes {}
$obj foreach file {
     if {[info exists pathes([file dirname $file])]} {
        incr pathes([file dirname $file])
     } else {
        set pathes([file dirname $file]) 1
     }
}

# print pathes and find the biggest
foreach {name value} [array get pathes] {
     puts "$name : $value"
}

这个需要在tcl的基础上安装tcllib。请运行以下命令:sudo apt-get install tcllib tcl tk。 - Bimo

2

如果需要快速(1级)文件模式匹配,请使用以下方法:

glob **/*.c

如果您想进行递归搜索,请使用以下命令:
proc ::findFiles { baseDir pattern } {
  set dirs [ glob -nocomplain -type d [ file join $baseDir * ] ]
  set files {}
  foreach dir $dirs { 
    lappend files {*}[ findFiles $dir $pattern ] 
  }
  lappend files {*}[ glob -nocomplain -type f [ file join $baseDir $pattern ] ] 
  return $files
}

puts [ join [ findFiles $basepath "*.tcl" ] \n ]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接