我想在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} *;
我尝试支持'*',但没有解决问题。请求帮助......
答案 0 :(得分:2)
假设当前工作目录中存在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不处理通配或将事物扩展为多个参数。相反,你应该写这样的东西:”
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
}}
}
}