如何在Tcl中替换以某些字符串开头的行?在Tcl中使用bash是不对的?

时间:2013-01-31 21:05:51

标签: bash replace sed tcl

我正在编写Tcl脚本,其中一部分包含用另一行替换包含某些字符串模式的第一次出现的行。我使用sed作为Tcl内部的bash命令,如下所示:

exec bash -c {sed 0,/Apple/{s/Apple/Banana/ File}

我的问题是有没有直接的方法来使用Tcl命令,也是错误或不建议在Tcl中使用大量的Bash命令?

由于

4 个答案:

答案 0 :(得分:5)

确实有一个regsub命令:

regsub -- {Apple} $line Banana line

这是the official documentation.

如果您需要帮助阅读文件的第一行,this page可能会有所帮助。

答案 1 :(得分:1)

您可以使用[string]命令组合执行此操作:

proc replaceFirst {text find replace} {
    set idx [string first $find $text]
    if {$idx == -1} {return $text}     ;# search string not found in text
    set end [expr {$idx + [string length $find] - 1}]
    string replace $text $idx $end $replace
}

replaceFirst "I hear Apple makes many popular Apple products." Apple Banana
# => I hear Banana makes many popular Apple products.

答案 2 :(得分:0)

如果要替换文本块中的字符串:

set text [string map {Apple Banana} $text]

如果您想更新文件中的字符串,fileutil包只包含票证:fileutil::updateInPlace

package require fileutil
proc processLine {line} { return [string map {Apple Banana} $line] }
fileutil::updateInPlace file.txt processLine

请注意,string map命令可以一次替换多个字符串:

string map {Apple Banana Monkey Ape Coke Pepsi} $text

更新

事实证明,字符串映射将取代所有Apple实例,这不是艾哈迈德想要的(感谢Glenn指出这一点)。我们应该使用acheong87的regsub解决方案:

package require fileutil
proc processLine {line} { return [regsub -- {Apple} $line "Banana"] }
fileutil::updateInPlace file.txt processLine

答案 3 :(得分:0)

首先,在这里伸出sed看起来很整洁(由于sed的陈述性表达性)但是多余并且因为添加每个“活动部分”而使你的程序维护更加困难复杂性。

基本上,在普通Tcl中重新实现代码段所需的步骤是:

  1. 打开源文件。
  2. 反复调用文件频道上的gets以逐行读取数据。
  3. 在每一行上对regsub执行正确构造的调用,这会尝试将“Apple”替换为“Banana”。
  4. 一旦对regsub的调用返回1或更多意味着该字符串与您的正则表达式匹配,请退出文件读取循环。
  5. 其余的实现取决于您对数据的处理方式。

    其次,即使你选择从你的Tcl脚本执行sed,你肯定不需要在这里涉及shell,因为Tcl的exec命令能够处理命令管道和流重定向本身。

    当前方法的另一个非显而易见的问题是,在另一个脚本(对于shell)中内联一个脚本(对于sed)可能很容易创建逃避噩梦:尝试思考如果您的源模式或您的源模式会发生什么替换模式可能是任意数据,可以包含空格字符以及单引号和双引号。

    第三,当你需要调用一个shell 时,永远不要打电话给bash,除非你真的想要需要在{<3}}中使用bashism你传递给shell的脚本。在所有其他99.9%的情况下,您应该调用/bin/sh而不是标准shell的标准路径,该标准shell保证为其运行的脚本实现POSIX shell语义。这样做的原因是某些系统(特别是Debian及其至少一些衍生产品)的/bin/sh链接到另一个shell(在Debian中,它是dash),缺少{{1}的交互功能但作为交换,它启动并更快地运行其脚本。