有没有一种方法可以在Tcl中对字符串执行POSIX shell转义?
背景:
我有一个包含任意文件名的Tcl列表。 我需要扩展该列表以粘贴到后面将通过execing“sh -c”执行的任意POSIX shell(bash,dash,posh等)的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 中有一个 %q 的格式化程序可以满足我的需求。我可以针对每个文件名调用一次 Bash 来利用这个功能,但这会使脚本变得很臃肿,并且还会引入对 Bash 的依赖,而我并不希望这样做。
按照 POSIX 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转义字符串?如果有标准的方法,我会非常高兴,但是如果只有非标准的Tcl库或甚至可以从C中调用的方法也可以让我满意。请注意保留HTML标记。
$name
以重定向字符如>
开头,那么posix_escape_via_bash
将会遇到问题。exec
充满了陷阱... - Donal Fellows