替换C文件行的TCL脚本

替换C文件行的TCL脚本,tcl,Tcl,我有一个C文件 C:\SVN\Code\fileio.C 这会将2个音频文件读取为 tuningFile = fopen("../../simulation/micdata.bin", "rb"); mic1File = fopen("../../simulation/mic1.pcm", "rb"); 我需要编写TCL脚本代码来读取C文件,并将这两个实例替换为 tuningFile = fopen("C:/SVN/simulation/micdata.bin", "rb");

我有一个C文件

C:\SVN\Code\fileio.C

这会将2个音频文件读取为

tuningFile = fopen("../../simulation/micdata.bin", "rb");   
mic1File = fopen("../../simulation/mic1.pcm", "rb");
我需要编写TCL脚本代码来读取C文件,并将这两个实例替换为

tuningFile = fopen("C:/SVN/simulation/micdata.bin", "rb");    
mic1File = fopen("C:/SVN/simulation/mic1.pcm", "rb");
任何人都可以举一个简单的例子来说明以下内容:

  • 逐行读取文件
  • 搜索类似tuningFile=fopen的内容(
  • 从中提取路径并将其更改为绝对路径
  • 将其与*tuningFile=fopen(
  • 在同一位置用修改后的行替换原始行
谢谢

sedy

关键是您实际上想要替换:

fopen("../../simulation/

使用
字符串映射
很容易做到这一点。接下来的问题只是执行文件I/O,几乎任何可以由普通编译器编译的C源文件都可以通过一次将其全部加载到内存中得到最佳处理:

set filename {C:\SVN\Code\fileio.c}
set mapping [list {fopen("../../simulation/} {fopen("C:/SVN/simulation/}]

# Slurp the file in
set f [open $filename]
set data [read $f]
close $f

# Apply the mapping
set data [string map $mapping $data]

# Make the original a backup
file rename $filename $filename.bak

# Write back with a separate open
set f [open $filename w]
puts -nonewline $f $data
close $f

如果愿意,您可以使用,例如,
[lindex$argv 0]
获取文件名作为参数。代码的其余部分并不重要。

关键是您实际上想要替换:

fopen("../../simulation/
package require fileutil

set filename C:/SVN/Code/fileio.c
set mapping [list {fopen("../../simulation/} {fopen("C:/SVN/simulation/}]

proc replace {mapping data} {
    string map $mapping $data
}

::fileutil::updateInPlace $filename [list replace $mapping]

使用
字符串映射
很容易做到这一点。接下来的问题只是执行文件I/O,几乎任何可以由普通编译器编译的C源文件都可以通过一次将其全部加载到内存中得到最佳处理:

set filename {C:\SVN\Code\fileio.c}
set mapping [list {fopen("../../simulation/} {fopen("C:/SVN/simulation/}]

# Slurp the file in
set f [open $filename]
set data [read $f]
close $f

# Apply the mapping
set data [string map $mapping $data]

# Make the original a backup
file rename $filename $filename.bak

# Write back with a separate open
set f [open $filename w]
puts -nonewline $f $data
close $f
如果愿意的话,可以使用
[lindex$argv 0]
将文件名作为参数获取。代码的其余部分不在乎

package require fileutil

set filename C:/SVN/Code/fileio.c
set mapping [list {fopen("../../simulation/} {fopen("C:/SVN/simulation/}]

proc replace {mapping data} {
    string map $mapping $data
}

::fileutil::updateInPlace $filename [list replace $mapping]
应该也可以。(从Donal中删除了
映射的定义)。
updateInPlace
在其第二个参数中调用命令前缀,将文件的内容传递给该命令,并使用命令的结果更新文件

这与Donal的回答中的步骤非常接近,用更高级别的代码表示。如果需要备份副本,请在调用
updateInPlace
之前执行此操作:

file copy $filename [file rootname $filename].bak
文件:文件包

应该也可以。(从Donal中删除了
映射的定义)。
updateInPlace
在其第二个参数中调用命令前缀,将文件的内容传递给该命令,并使用命令的结果更新文件

这与Donal的回答中的步骤非常接近,用更高级别的代码表示。如果需要备份副本,请在调用
updateInPlace
之前执行此操作:

file copy $filename [file rootname $filename].bak

文档:包,

这是一个提取文件名并在其上使用
文件规范化的版本:

set f [open $filename r]
set code [read $f]
close $f

set code [subst -novar -noback [regsub -all {((?:tuningFile|mic1File) = fopen\(")([^"]+)} $code {\1[file normalize "\2"]}]]
打破这种局面

  • 此命令

    regsub -all {((?:tuningFile|mic1File) = fopen\(")([^"]+)} $code {\1[file normalize "\2"]}
    
    将找到字符串
    tuningFile=fopen(../relative/file
    (或“mic1file=…”),并将其替换为文本

    tuningFile = fopen("[file normalize "../relative/file"]
    
  • 然后我们将其馈送到
    subst
    ,以便可以替换嵌入的命令,执行
    文件规范化
    命令,生成文本

    tuningFile = fopen("/full/path/to/file
    

  • 第2步:在C代码中处理括号

    $ pwd
    /home/jackman/tmp/base/SVN/Code
    
    $ tree ../..
    ../..
    ├── SVN
    │   └── Code
    │       ├── fileio.c
    │       └── normalize.tcl
    └── simulation
        ├── mic1.pcm
        └── micdata.bin
    
    3 directories, 4 files
    
    $ cat fileio.c 
    int tuningFix[MAXTUNING];
    tuningFile = fopen("../../simulation/micdata.bin", "rb");   
    mic1File = fopen("../../simulation/mic1.pcm", "rb");
    
    $ cat normalize.tcl 
    #! tclsh
    package require fileutil
    set code [fileutil::cat [lindex $argv 0]]
    
    # protect existing brackets
    set bracketmap [list \[ \x01 \] \x02]
    set code [string map $bracketmap $code]
    
    # normalize filenames
    set code [
        subst -novar -noback [
            regsub -all {((?:tuningFile|mic1File) = fopen\(")([^"]+)} $code {\1[file normalize "\2"]} 
        ]
    ]
    
    # restore brackets
    set code [string map [lreverse $bracketmap] $code]
    
    puts $code
    
    $ tclsh normalize.tcl fileio.c 
    int tuningFix[MAXTUNING];
    tuningFile = fopen("/home/jackman/tmp/base/simulation/micdata.bin", "rb");   
    mic1File = fopen("/home/jackman/tmp/base/simulation/mic1.pcm", "rb");
    

    以下是一个提取文件名并在其上使用
    文件规范化的版本:

    set f [open $filename r]
    set code [read $f]
    close $f
    
    set code [subst -novar -noback [regsub -all {((?:tuningFile|mic1File) = fopen\(")([^"]+)} $code {\1[file normalize "\2"]}]]
    
    打破这种局面

  • 此命令

    regsub -all {((?:tuningFile|mic1File) = fopen\(")([^"]+)} $code {\1[file normalize "\2"]}
    
    将找到字符串
    tuningFile=fopen(../relative/file
    (或“mic1file=…”),并将其替换为文本

    tuningFile = fopen("[file normalize "../relative/file"]
    
  • 然后我们将其馈送到
    subst
    ,以便可以替换嵌入的命令,执行
    文件规范化
    命令,生成文本

    tuningFile = fopen("/full/path/to/file
    

  • 第2步:在C代码中处理括号

    $ pwd
    /home/jackman/tmp/base/SVN/Code
    
    $ tree ../..
    ../..
    ├── SVN
    │   └── Code
    │       ├── fileio.c
    │       └── normalize.tcl
    └── simulation
        ├── mic1.pcm
        └── micdata.bin
    
    3 directories, 4 files
    
    $ cat fileio.c 
    int tuningFix[MAXTUNING];
    tuningFile = fopen("../../simulation/micdata.bin", "rb");   
    mic1File = fopen("../../simulation/mic1.pcm", "rb");
    
    $ cat normalize.tcl 
    #! tclsh
    package require fileutil
    set code [fileutil::cat [lindex $argv 0]]
    
    # protect existing brackets
    set bracketmap [list \[ \x01 \] \x02]
    set code [string map $bracketmap $code]
    
    # normalize filenames
    set code [
        subst -novar -noback [
            regsub -all {((?:tuningFile|mic1File) = fopen\(")([^"]+)} $code {\1[file normalize "\2"]} 
        ]
    ]
    
    # restore brackets
    set code [string map [lreverse $bracketmap] $code]
    
    puts $code
    
    $ tclsh normalize.tcl fileio.c 
    int tuningFix[MAXTUNING];
    tuningFile = fopen("/home/jackman/tmp/base/simulation/micdata.bin", "rb");   
    mic1File = fopen("/home/jackman/tmp/base/simulation/mic1.pcm", "rb");
    

    基于所有发表评论的用户的巨大帮助,我能够按要求完成任务

    proc replaceFileTemp {} {
        global pth_fileio_orig
    
        # create backup for copy back
        set pth_backup [file rootname $pth_fileio_orig].bak
        file copy $pth_fileio_orig $pth_backup
    
        #get current file path
        set thisFilePth [ dict get [ info frame [ info frame ] ] file ]
    
        # get folder for current file
        set thisFileFolderPth [file dirname $thisFilePth]
    
        # set the replacement string/path
        set replacementPth [file dirname $thisFileFolderPth]
    
    
        # obtain original string to be replaced 
        set origPth "../../simulation/toplevel"
    
        # download package for file manipulation
        package require fileutil
    
    
        set mapping [list $origPth $replacementPth]
        proc replace {mapping data} {
        string map $mapping $data
        }
    
        # replace original string with replacement string for all occurrences in file
        ::fileutil::updateInPlace $pth_fileio_orig [list replace $mapping]
    }
    
    # set the path to toplevel C file
    set pth_fileio_orig [file normalize "../../../fileio.c"]
    replaceFileTemp
    

    基于所有发表评论的用户的巨大帮助,我能够按要求完成任务

    proc replaceFileTemp {} {
        global pth_fileio_orig
    
        # create backup for copy back
        set pth_backup [file rootname $pth_fileio_orig].bak
        file copy $pth_fileio_orig $pth_backup
    
        #get current file path
        set thisFilePth [ dict get [ info frame [ info frame ] ] file ]
    
        # get folder for current file
        set thisFileFolderPth [file dirname $thisFilePth]
    
        # set the replacement string/path
        set replacementPth [file dirname $thisFileFolderPth]
    
    
        # obtain original string to be replaced 
        set origPth "../../simulation/toplevel"
    
        # download package for file manipulation
        package require fileutil
    
    
        set mapping [list $origPth $replacementPth]
        proc replace {mapping data} {
        string map $mapping $data
        }
    
        # replace original string with replacement string for all occurrences in file
        ::fileutil::updateInPlace $pth_fileio_orig [list replace $mapping]
    }
    
    # set the path to toplevel C file
    set pth_fileio_orig [file normalize "../../../fileio.c"]
    replaceFileTemp
    

    您最好创建一个带有更正的临时文件,并将实际文件替换为临时文件。我不能这样做。TCL脚本传递了一个参数,该参数决定是保留绝对路径还是相对路径。因此,我需要一种以编程方式更改它的方法。您最好创建一个带有更正的临时文件,并替换实际的fi我不能这样做。TCL脚本被传递了一个参数,该参数决定是保留绝对路径还是相对路径。因此,我需要一种以编程方式对其进行更改的方法。我欣赏这种响应。但是,从相对路径到绝对路径的映射本身并不是固定的。因此,如果脚本在不同的计算机上运行,“../../simulation/可能会转换为其他内容,而不是“C:/SVN/simulation”。因此,我需要使用[file normalize$origfile],以便在使用相对路径读取该行后,它将用通过[file normalize$origfile]获得的绝对路径替换它。我很感谢您的响应。但是,从相对路径到绝对路径的映射本身并不是固定的。因此,如果脚本在不同的计算机上运行,“../../simulation/可能会转换为其他内容,而不是“C:/SVN/simulation”。因此,我需要[file normalize$origfile]要使用它,一旦用相对路径读取了行,它就会用通过[file normalize$origfile]获得的绝对路径来替换它。这本质上就是perl
    s/pattern/some code here/e
    Hi-Glenn的Tcl惯用用法,因为C代码的数组定义为int-tuningFix[MAXTUNING];解释器在从$code读取时将其视为命令并进行投诉。添加了处理代码中方括号的更新版本这本质上是perl
    s/pattern/some code here/e的Tcl惯用用法。嗨,Glenn,regsub命令对我来说失败,因为C代码的数组定义为int tuningFix[MAXTUNING];当从$code读取时,解释器将其视为命令并进行投诉。添加了处理代码中括号的更新版本