【发布时间】:2012-06-21 02:34:30
【问题描述】:
有没有办法在 Tcl 中对字符串执行 POSIX shell 转义?
背景:
我有一个 Tcl 列表中的任意文件名列表。我需要扩展列表以粘贴到稍后将由任意 POSIX shell(bash、dash、posh 等)通过执行“sh -c”执行的 shell 片段中。
这是一个说明问题的例子:
#!/usr/bin/tclsh
set targets {with\ spaces has"stray'quotes has{brackets} $not_a_variable \[escaped_braces\] (not_a_subshell) weird\ \{|#^$(}
set shell_fragment {
something
some_command $targets
something else
}
puts [subst $shell_fragment]
上面的输出是带有 Tcl 转义的名称:
something
some_command with\ spaces has"stray'quotes has{brackets} $not_a_variable \[escaped_braces\] (not_a_subshell) weird\ \{|#^$(
something else
然而,我需要它看起来正常工作是这样的(POSIX shell 转义):
something
some_command with\ spaces has\"stray\'quotes has{brackets} \$not_a_variable [escaped_braces] \(not_a_subshell\) weird\ {\|\#^\$\(
something else
想法:
以下是我可以想象的一些我不想做的解决方法:
-
在 Bash 中,有一个用于 printf 的 %q 格式化程序,它可以满足我的需求。我可以为每个文件名执行一次 bash 调用以利用此功能,但这 1) 是一个很大的后盾,并且 2) 引入了对 bash 的依赖,我不希望这样做。
李> 根据 POSIX shell 转义规则实现自己的 shell 转义。这显然可行,但我宁愿不重新发明轮子。我找到了一种“简单”的方法,通过发送垃圾引号来做到这一点,但这会使调试变得很糟糕,并大大减少了可用的命令行长度:
“坏”方法的示例:
proc posix_escape_via_bash {name} {
return [exec bash -c {printf %q "$0"} $name]
}
proc posix_escape_via_spamming_quotes {name} {
set escaped {}
foreach char [split $name {}] {
switch $char {
' {lappend escaped {\'}}
default {lappend escaped '$char'}
}
}
return [join $escaped {}]
}
再说一遍:有没有办法在 Tcl 中对字符串执行 POSIX shell 转义?如果有的话,我会很高兴有一种“标准”的方法,但我' d 也对非标准的 Tcl 库感到满意,甚至可以从 C 中做到这一点,所以我可以从 Tcl 中调用它。
【问题讨论】:
-
如果
$name以>之类的重定向字符开头,那么posix_escape_via_bash将遇到问题。exec布满陷阱...... -
@Donal 关于依赖 bash 的版本的好点;这也是我不能使用它的另一个原因!