【问题标题】:Using globs in Perl replace one liner in TCL script在 Perl 中使用 glob 替换 TCL 脚本中的一行
【发布时间】:2016-08-18 09:25:36
【问题描述】:

我想在 TCL 脚本中运行一个 Perl one liner,如下所示:

exec perl -i -pe {s/SUBSTRING/REPLACING_STRING/g} testFile;

这很好用。但是,如果我想修改下面的所有文件:

exec perl -i -pe {s/SUBSTRING/REPLACING_STRING/g} *;

它给了我错误信息:

Can't open '*': No such file or directory.
    while executing
exec perl -i -pe {s/SUBSTRING/REPLACING_STRING/g} *;

我尝试支撑'*',但没有解决问题。请求帮助...

【问题讨论】:

  • exec 不扩展通配符。如果将 * 替换为 {*}[glob *] 会发生什么?
  • 嗨,彼得,您的解决方案很有魅力。非常感谢。如果你能告诉我它是如何工作的,我会很高兴。

标签: tcl


【解决方案1】:

假设文件abc存在于当前工作目录中,在shell中执行echo *会打印a b c。这是因为 shell 命令求值器识别通配符,并在找到通配符表达式的零个或多个文件名列表中拼接。

Tcl 的命令评估器不能识别通配符,但会将它们原封不动地传递给被调用的命令。如果该命令可以使用通配符,它​​将这样做。 exec 命令不会,这意味着它将按原样将通配符表达式传递给由命令字符串命名的 shell 命令。

测试一下,我们得到

% exec echo *
*

因为我们要求 shell 执行的操作很简单

echo *

如果我们想要将通配符表达式扩展为文件名列表,我们需要显式调用glob 命令:

% exec echo [glob *]
"a b c"

这仍然不太正确,因为列表没有自动拼接到命令字符串中:而是 shell 得到了

echo {a b c}

(注意:这里我在 Windows 上伪装echo,实际输出可能不同。)

为了同时展开拼接文件名列表,我们需要这样:

% exec echo {*}[glob *]
a b c

{*} 前缀告诉 Tcl 命令评估器替换以下参数,就好像由它产生的单词是原始命令行中的参数一样。

echo a b c

这个例子的解释比我在这里给出的更简洁,在exec的文档中:

“如果你正在转换涉及 shell globbing 的调用,你应该记住 Tcl 默认不处理 globbing 或将事物扩展为多个参数。相反,你应该这样写:”

exec ls -l {*}[glob *.tcl]

PS:

如果已经加载了fileutil 包:

package require fileutil

这也可以用 Tcl 写成单行:

foreach file [glob *] {::fileutil::updateInPlace $file {apply {str {regsub -all SUBSTRING $str REPLACING_STRING}}}}

或为了可读性而使用换行符和缩进:

foreach file [glob *] {
    ::fileutil::updateInPlace $file {
        apply {str {
            regsub -all SUBSTRING $str REPLACING_STRING
        }}
    }
}

文档:applyexecfileutil 包、foreachglobpackageregsub{*}

【讨论】:

  • Windows 上有一个echo(前提是您使用auto_execok,因为它是内置的shell),但这与您所说的主旨无关。 Shell 在扩展方面不如 Tcl 谨慎,这就是造成问题的原因。扩展一个 glob 是正确的答案。
  • 非常感谢彼得的详细解释。这肯定有很大帮助。再次感谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-26
  • 1970-01-01
  • 1970-01-01
  • 2017-04-30
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多