1

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

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

我的问题是有没有使用 Tcl 命令的直接方法,在 Tcl 中使用大量 Bash 命令是错误的还是不推荐?

谢谢

4

4 回答 4

5

有一个regsub命令可以做到这一点:

regsub -- {Apple} $line Banana line

这是官方文档。

如果您在阅读文件的第一行时需要帮助,此页面可能会有所帮助。

于 2013-01-31T21:49:00.013 回答
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.
于 2013-02-01T20:21:55.143 回答
0

首先,在这里伸出援手sed似乎很整洁(由于sed's 的声明性表达),但是多余的并且使您的程序的维护更加困难,因为添加每个“移动部分”会增加复杂性。

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

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

实施的其余部分取决于您对数据的处理方式。

其次,即使您选择sed从您的 Tcl 脚本执行,您当然也不需要在此处涉及 shell,因为 Tcl 的exec命令能够自行处理命令管道和流重定向。

您当前方法的另一个不明显的问题是,将一个脚本 (for sed) 内联到另一个脚本 (for shell) 中可能很容易造成逃避噩梦:尝试考虑如果您的源模式或替换模式可能是任意数据会发生什么包含空格字符以及单引号和双引号。

bash第三,当你需要调用shell时,永远不要调用,除非你真的意味着你需要在传递给 shell 的脚本中有一个bashism。在所有其他 99.9% 的情况下,您应该调用/bin/sh它,它是标准 shell 的标准路径,它保证为它运行的脚本实现 POSIX shell 语义。这样做的原因是某些系统(特别是 Debian 和至少它的一些衍生产品)已经/bin/sh链接到另一个 shell(在 Debian 中是 it's dash),该 shell 缺乏交互功能,bash但作为交换,它可以更快地启动和运行其脚本。

于 2013-02-02T07:01:26.590 回答
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 的所有实例,这不是 Ahmed 想要的(感谢 Glenn 指出这一点)。我们应该使用 acheong87 的 regsub 解决方案:

package require fileutil
proc processLine {line} { return [regsub -- {Apple} $line "Banana"] }
fileutil::updateInPlace file.txt processLine
于 2013-02-01T18:57:38.970 回答