【问题标题】:TCL exec with variable arg string starting with specials characters like <, >, or |TCL exec 变量 arg 字符串以 <、> 或 | 等特殊字符开头
【发布时间】:2019-07-27 05:44:44
【问题描述】:

我正在尝试从 tcl 到 exec,传递一个可以以 &lt;(或 | 或 &gt;)开头的变量作为参数。 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>"

在硬编码字符串时,我什至无法得到预期的&lt;hi&gt;

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,但&lt; 抛出了那里的解决方案

另外,也许值得注意

1) 有额外的参数允许| 通过,但不允许&lt;

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 中让所有人都接受它;对于大多数代码中幸运地很少见的问题来说,这简直是太痛苦了。)

标签: escaping tcl


【解决方案1】:

我不太了解您要做什么,但通过四处搜索,我找到了this post(因为那不太奏效......)和this post。总之,似乎以下工作:

% exec bash -c {echo "<hi>"}
<hi>

在第一个链接上引用 Colin:

Tcl 的 exec 不调用 bash 或自行进行此转换。您可以通过从 Tcl 显式调用 bash 来使其工作

【讨论】:

  • 啊,这似乎是解决问题的好方法——让另一个解释器处理转义。它让我走到了一半。使用变量是棘手的部分set cmd {&lt;hi&gt;}; exec bash -c {*}[list echo $cmd] 仍然抱怨'无法读取文件“hi>”'
  • @Will 抱歉,我在看别的东西,我玩了一会儿,发现这可以工作exec bash -c [list echo '$cmd'](使用双引号甚至硬编码命令导致“意外令牌换行符附近的语法错误"
  • 你不能在这里展开列表,因为它会导致exec bash -c echo $cmd,这违背了将整个命令发送到bash的目的。
【解决方案2】:

解决这个问题的一种方法(从@jerry 窃取一点)是将命令写入临时文件并使用 shell 运行它

   set f [file tempfile fn "/tmp/cmd"]
   # open $fn w # unnecessary
   puts $f $cmd
   close $f
   set shcmd "echo \"`cat $fn`\""
   exec sh -c $shcmd 
   file delete $fn

【讨论】:

  • 你不需要在那个脚本中open $fn w; $f 此时已经打开并可写。
猜你喜欢
  • 1970-01-01
  • 2018-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多