【发布时间】:2019-07-27 05:44:44
【问题描述】:
我正在尝试从 tcl 到 exec,传递一个可以以 <(或 | 或 >)开头的变量作为参数。 tcl 似乎认为我想将文件的输入定向到命令而不是使用文字尖括号。
set cmd "<hi>"
exec echo $cmd # couldn't read file "hi>"
eval exec [list echo $cmd] # couldn't execute "echo <hi>"
eval exec {*}[list echo $cmd] # couldn't read file "hi>"
在硬编码字符串时,我什至无法得到预期的<hi>
eval exec {*}{"echo" <hi>} # couldn't read file "hi>"
exec echo {"<hi>"} # "<hi>" # but I don't want quotes
exec echo {\<hi>} # \<hi> # nor a leading \
exec echo {<hi>} # couldn't read file "hi>"
exec echo {*}[list "<hi>"] # '
eval exec echo [list "<hi>"] # '
这类似于TCL exec with special characters in list,但< 抛出了那里的解决方案
另外,也许值得注意
1) 有额外的参数允许| 通过,但不允许<
eval exec {*}[list echo {|foo bar} ] # |foo bar # WORKS? WHAT?
eval exec {*}[list echo {|foo} ] # illegal use of | or |& in command
eval exec {*}[list echo {<foo bar} ] # couldn't read file "foo"
2) 额外的空格或字符足以解决问题(但如何使用用户提供/解析的变量)
exec echo { <hi>} # <hi> # with leading space
exec echo { |hi} # |hi # with leading space
exec echo [list " " $cmd] # { } <hi> # not useful
exec echo {*}[list " " $cmd] # couldn't read file "hi>"
exec echo [join [list "" $cmd]] # <hi> # leading space
exec echo [string trim [join [list "" $cmd]]] # couldn't read file "hi>"
【问题讨论】:
-
您发现
exec(和open |…)的工作方式存在一个长期存在的问题。使用从属 bash shell 是最简单的解决方法,您无法通过从文件或管道进行重定向来做到这一点。此外,重定向是唯一一种二进制安全的技术。您不能将任意二进制数据作为命令行参数传递(因为 NUL 字节始终是操作系统的参数结束指示符)。 -
问题在于,这是 Tcl 将语言级语法与命令级语法分离的一个地方,实际上并没有帮助。这些修复在概念上很简单,但会破坏现有代码并使启动子进程变得更加困难。我猜我们最终将不得不为此创建一个单独的命令并让脚本选择使用哪个。 (我真的不认为我们会在 9.0 中让所有人都接受它;对于大多数代码中幸运地很少见的问题来说,这简直是太痛苦了。)