在Tcl中,如何在传递给`exec`时阻止变量的内容被shell解释?

时间:2016-07-27 20:15:44

标签: tcl interpolation io-redirection csh

我正在维护一些旧代码并发现以下内容......

if {[catch {exec -- echo $html_email > $file} ret]} {
    puts $ret
    return 0
}

...由于HTML电子邮件的第一个字符为<

而中断
couldn't read file "html>
    <title>cama_Investigate 00000560554PONY1</title>
    <style type="text/css">
    ...
    ...
    ...

被解释为I / O重定向运算符。以前这不是问题因为我们用一些标题开始发送电子邮件,例如

append html_email "Content-Type       : text/html; charset=us-ascii\n"
append html_email "Content-Disposition: inline\n"

我将重写所有这些以使用Tcl的本机文件I / O,因此这个问题主要是学术性的:当传递给{{1}时,保护变量内容不被shell解释的正确方法是什么? }?

我正在使用Tcl 8.0.5和csh,但如果可能的话,我对一般答案感兴趣。

2 个答案:

答案 0 :(得分:2)

Tcl&#39; exec很时髦,唉。它坚持解释以<字符作为重定向开头的参数。 (还有一些其他的,但你不太可能击中它们。)除了将数据写入临时文件并从中重定向之外,没有一般的解决方法。

set ctr 0
while 1 {
    set filename /tmp/[pid].[incr ctr].txt
    # POSIX-style flags; write-only, must create or generate error
    if {[catch {open $filename {WRONLY CREAT EXCL}} f] == 0} break
}
puts $f $html_email
close $f
exec echo <$filename >$file
file delete $filename

这非常复杂!通过改变我们使用的程序,我们可以做得更好。如果我们使用echo而不是cat,我们可以使用exec的heredoc语法:

exec cat <<$html_email >$file

因为在这种情况下,字符直接通过管道传递(这是Tcl如何做到这一点),所以不会出错。然而它仍然仍然愚蠢,因为Tcl完全能够直接写入文件,更便携,并且开销更少:

set f [open $file "w"]
puts $f $html_email
close $f

是的,这实际上是上面第一个示例的一般替换非常简化的版本。让我们做一些更加明显正确的简单事情,因为那时未来会有更少的惊喜。

答案 1 :(得分:0)

您可以间接调用目标命令,通过shell路由它:

exec -- csh -c "echo '$html_email'" > $file

exec -- csh -c "exec echo '$html_email'" > $file