2012-06-19 1 views
4

Используя старый ответ на поиск файла в Tcl: https://stackoverflow.com/a/435094/984975TCL глубоко рекурсивный поиск файлов, поиск файлов с расширением * .c

Сначала давайте обсудим, что я делаю прямо сейчас: Использование этой функции: (кредит 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 файлов. Однако, если бы я мог перечислять все файлы и их пути, я мог бы подсчитать, сколько файлов находится в каждом каталоге и получить тот, у которого наибольший счет.

+0

Ошибка происходит из слишком старой версии Tcl, попробуйте использовать более свежий Tcl, вам нужно как минимум Tcl 8.4 (которому всего 10 лет ...). – schlenk

+0

Если я сделаю имена моих каталогов с пробелами в конце (что является законным для большинства систем, но очень сложно!), Этот код полностью обречен! Bwahahaha! (Не 'string trim' вещи, которые выходят из' glob' ...) –

ответ

3

Вы используете старую версию Tcl. [file normalize] был представлен в Tcl 8.4 примерно в 2002 году или около того. Обновите уже.

Если вы не можете - тогда вы используете 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] 
+0

Это отлично работает, не могли бы вы добавить комментарии, чтобы помочь мне (и другим) понять код? – zehelvion

3

Я хотел бы использовать функцию ::fileutil::traverse, чтобы сделать это.

Что-то вроде:

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" 
} 
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 ] 

 Смежные вопросы

  • Нет связанных вопросов^_^