从 Tcl 中的多个文件中读取特定数据

Posted

技术标签:

【中文标题】从 Tcl 中的多个文件中读取特定数据【英文标题】:Reading specific data from multiple files in Tcl 【发布时间】:2021-11-03 00:31:38 【问题描述】:

我正在编写一个 TCL 脚本来读取多个文件并使用正则表达式在它们中搜索包含特定单词的行。我已经能够从文件中搜索一件事。但是我需要修改脚本以在脚本中搜索多个内容,将在一个文件中找到的项目一起打印在一行中,然后在第二行中从另一个文件中找到的项目。 我写了这个

foreach fileName [glob  /home/kartik/tclprac/*/*] 
#   puts " Directories present are: [file tail $fileName]" 
    set fp [open $fileName "r"]
    while  [gets $fp data]>=0  
    if [regexp set Date* $data] | [regexp set Channel*  $data]  
    #puts "file: [file dirname $fileName] data: $data"
    set information "file: [file dirname $fileName] data: $data"
    puts $information
    set fp2 [open output.txt "a"]
    puts $fp2 $information




现在我得到的输出为:

file: /home/kartik/tclprac/wire_3 data: set Date 02/08/2021 
file: /home/kartik/tclprac/wire_2 data: set Date 01/08/2021
file: /home/kartik/tclprac/wire_1 data: set Channel Disney 
file: /home/kartik/tclprac/wire_1 data: set Date 31/07/2021

我想要的是类似的东西

file: /home/kartik/tclprac/wire_3 data: set Date 02/08/2021 
file: /home/kartik/tclprac/wire_2 data: set Date 01/08/2021 
file: /home/kartik/tclprac/wire_1 data: set Date 31/07/2021 set Channel Disney

【问题讨论】:

请注意,| 是数学上的“或”。使用|| 表示布尔“或”。 关键是不要立即打印信息:建立一个匹配行的列表,然后在阅读完文件后打印出加入的列表。 另外,关闭你打开的文件句柄,否则你可能会用完它们。 另外,你只需要在foreach循环开始之前打开一次output.txt 【参考方案1】:

在我看来,您希望将单个文件的结果收集到一行,而不是为每个匹配行打印一行(传统的 grep 工具方法),每行结果被分开按空格。

我们可以这样做,但是如果我们将代码分成几个过程(一个用于处理单个文件的内容,另一个用于整个作业),它会变得更清晰。

proc processFileContents name contents accumulatorChannel 
    set interesting [lmap line [split $contents "\n"] 
        if ![regexp set (?:Date|Channel)  $line] 
            # SKIP non-matching lines
            continue
        
        # Trim the matching lines
        string trim $line
    ]
    # If we matched anything, print out
    if [llength $interesting] 
        set information "file: $name data: [join $interesting \n]"
        puts $information 
        puts $accumulatorChannel $information
    


proc processFilesInDir pattern accumulatorChannel 
    foreach fileName [glob -nocomplain -type f $pattern] 
        set channel [open $fileName]
        set contents [read $channel]
        close $channel

        processFileContents $fileName $contents $accumulatorChannel
    


set accum [open output.txt "a"]
processFilesInDir /home/kartik/tclprac/*/* $accum
close $accum

如果您使用的是没有lmap(8.5 或更早版本)的旧版本 Tcl,那么您可以使用foreach 编写它(因为lmap 实际上只是foreach 的收集形式; 唯一的区别是lmap 使用隐藏的临时变量来进行累加):

proc processFileContents name contents accumulatorChannel 
    set interesting 
    foreach line [split $contents "\n"] 
        if ![regexp set (?:Date|Channel)  $line] 
            # SKIP non-matching lines
            continue
        
        # Trim the matching lines
        lappend interesting [string trim $line]
    
    # If we matched anything, print out
    if [llength $interesting] 
        set information "file: $name data: [join $interesting \n]"
        puts $information 
        puts $accumulatorChannel $information
    

【讨论】:

在你问之前,不,你不能从 Tcl 代码中访问 lmap 的隐藏临时。它只存在于 C 或字节码空间中(取决于 Tcl 代码的编译方式,这不是重要的事情)并且实际上没有您的 Tcl 代码可以看到的名称。 嗨。你能解释一下这部分吗if ![regexp set (?:Date|Channel) $line] # SKIP non-matching lines continue # Trim the matching lines string trim $line

以上是关于从 Tcl 中的多个文件中读取特定数据的主要内容,如果未能解决你的问题,请参考以下文章

从 S3 读取大型 JSON 文件 (3K+) 并从数组中选择特定键

如何从 Apache Pig 中的文件中读取多个文件?

xilinx vivado:从tcl中读取组件.xml文件到项目中。

如何从R中的大型固定宽度文件中读取特定列

从特定行读取 csv

PowerShell - 从 csv 文件读取数据,比较特定列中的数据并将结果写入新文件