TCL - 将 STDIN 提供给 exec

TCL - feeding STDIN to exec

我正在尝试在使用 TCL 执行外部程序时实现重试机制。我在尝试将 STDIN 提供给外部程序时遇到了一些问题。我现在正在使用一个简化的示例来尝试解决该问题。采用以下 python 脚本 (simple.py):

x = raw_input()
y = raw_input()
print x + y

从输出中输入2个字符串将是字符串的连接结果。

现在以下命令可以从 TCL 解释器运行:

% exec python stuff.py << 1\n2
12

然而,当我尝试将其拆分为单独的命令,或在执行此操作之前将它们添加到字符串中时,它失败了。

失败 1:

% set cmd "python simple.py << 1\n2"
% exec $cmd
couldn't execute "python simple.py << 1
2": no such file or directory

失败 2:

% set cmd1 "python simple.py"
% set cmd2 "1\n2"
% exec $cmd1 << $cmd2

无法执行"python simple.py": 没有那个文件或目录

失败 3:

% set fullCommandString "exec python simple.py << 1\n2"
% eval $fullCommandString
Traceback (most recent call last):
  File "simple.py", line 2, in <module>
    y = raw_input()
EOFError: EOF when reading a line

第三种情况似乎启动了脚本,但它将 STDIN 的两行解释为一行。

感谢任何帮助。

默认情况下,Tcl 命令不会重新解释其参数中的空格。 exec 就是其中之一,它遵循相同的规则。这意味着您需要告诉 Tcl 将该单词列表 解释为单词列表 ,否则它只是一个字符串。幸运的是,这里有 {*};扩展 operator 语法将单词的其余部分解释为 Tcl 列表,并在您编写它的位置使用该列表之外的单词。我发现它非常有用。

最简单的修复实际上是你的第二种情况:

% set cmd1 "python simple.py"
% set cmd2 "1\n2"
% exec {*}$cmd1 << $cmd2

您可以通过添加 Tcl 列表引号来修复第一个和第三个,以确保 1\n2 仍然被解释为单个单词(否则换行符是一个非常合理的列表项分隔符)。

% set cmd "python simple.py << {1\n2}"
% exec $cmd
% set fullCommandString "exec python simple.py << {1\n2}"
% eval $fullCommandString

虽然第三个可以写得更经济:

% set fullCommandString "exec python simple.py << {1\n2}"
% {*}$fullCommandString

根据经验,如果您在现代 Tcl 中看到 eval(注意:不是 namespace evalinterp evaluplevel) 那么这通常表明某些代码可以通过小心地切换到使用扩展来提高效率并减少错误。


tl;dr: 在第二个示例中将 {*} 放在 $cmd1 之前以获得惯用的修复。