1

我有一个文件包含带有文件路径的行。有时路径包含 SHELL 环境变量,我想检查文件是否存在。以下是我的解决方案:

set fh [open "the_file_contain_path" "r"]

while {![eof $fh]} { 
  set line [gets $fh]
  if {[regexp -- {\$\S+} $line]} {
    catch {exec /usr/local/bin/tcsh -c "echo  $line" } line
      if {![file exists $line]} {
        puts "ERROR: the file $line is not exists"
      }
  }
}

我确定有更优雅的解决方案而不使用

/usr/local/bin/ tcsh -c

4

3 回答 3

3

您可以在 regexp 命令中捕获变量名称并在 Tcl 的全局env数组中进行查找。此外,您使用eofwhile 条件意味着您的循环将多次交互(请参阅http://phaseit.net/claird/comp.lang.tcl/fmm.html#eof

set fh [open "the_file_contain_path" "r"]

while {[gets $fh line] != -1} { 
  # this can handle "$FOO/bar/$BAZ"
  if {[string first {$} $line] != -1} {
    regsub -all {(\$)(\w+)} $line {\1::env(\2)} new
    set line [subst -nocommand -nobackslashes $new]
  }

  if {![file exists $line]} {
    puts "ERROR: the file $line does not exist"
  }
}
于 2012-09-01T12:12:37.073 回答
2

首先,通常更容易(对于小文件,比如不超过 1-2MB)读取整个文件并将其读取到行中,而不是在循环split中使用getsand 。(命令非常快。)eofwhilesplit

其次,要进行替换,您需要字符串中要替换的位置,因此您使用regexp -indices. 这确实意味着您需要采取更复杂的方法来进行替换,string rangestring replace完成一些工作。假设您使用的是 Tcl 8.5……</p>

set fh [open "the_file_contain_path" "r"]

foreach line [split [read $fh] "\n"] {
    # Find a replacement while there are any to do
    while {[regexp -indices {\$(\w+)} $line matchRange nameRange]} {

        # Get what to replace with (without any errors, just like tcsh)
        set replacement {}
        catch {set replacement $::env([string range $line {*}$nameRange])}

        # Do the replacement
        set line [string replace $line {*}$matchRange $replacement]
    }

    # Your test on the result
    if {![file exists $line]} {
        puts "ERROR: the file $line is not exists"
    }
}
于 2012-09-02T10:12:05.703 回答
0

TCL 程序可以使用内置的全局变量读取环境变量env。阅读该行,查找$后跟名称,查找$::env($name),并将其替换为变量。

如果文件是由不受信任的用户提供的,那么使用 shell 会非常糟糕。如果他们把; rm *文件放进去怎么办?如果你要使用 shell,你至少应该使用 sh 或 bash,而不是 tcsh。

于 2012-09-01T07:44:09.433 回答