假设文件a、b和c存在于当前工作目录中,在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
}}
}
}
文档:apply、exec、fileutil 包、foreach、glob、package、regsub、{*}