[英]running TCL through python by subprocess, but not giving any output
我正在尝试通过 python 子进程运行我的 tcl 脚本,如下所示:
import subprocess
>>> subprocess.Popen(["tclsh", "tcltest.tcl"])
<subprocess.Popen object at 0x0000000001DD4DD8>
>>> subprocess.Popen(["tclsh", "tcltest.tcl"], shell=True )
<subprocess.Popen object at 0x0000000002B34550>
我不知道它是否有效,因为我没有看到任何东西,我的 tcl 脚本也有一些来自我公司的包,当我使用 Tkinter、Tk 和 eval 时会导致错误,
import Tkinter
import socket
def TCLRun():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 5006))
root = Tkinter.Tk()
## root.tk.eval('package require Azimuth-Sdk')
tcl_script ="""
##package require Company-Sdk
## set players [ace_azplayer_list_players]
set players 2
puts $players
## if { $players != "" } {
## foreach player $players {
## set cmd ace_azplayer_remove_player
## if { [catch { [ $cmd $player ] } err] } {
## puts " $cmd $player - $err"
## sleep 1
## }
## }
## } """
# call the Tkinter tcl interpreter
root.tk.call('eval', tcl_script)
root.mainloop()
给我这个错误
import TCLCall
>>> TCLCall.TCLRun()
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
TCLCall.TCLRun()
File "C:\Users\XXX\Desktop\PKT\TCLCall.py", line 24, in TCLRun
root.tk.call('eval', tcl_script)
TclError: can not find channel named "stdout"
这就是为什么我切换到子流程。 至少它不会给我错误!
知道如何通过 python 使用内部所需包运行我的 tcl 脚本吗?!
谢谢
要使用subprocess.Popen
获取输出,您可以尝试以下操作:
import subprocess
p = subprocess.Popen(
"tclsh tcltest.tcl",
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
print stdout
print stderr
您使用subprocess.Popen
运行的脚本完全有可能也会生成错误,但不会显示,因为您没有明确查找它。
编辑:
为了防止在下面的评论中丢失一些信息:
您可能在这里有几个潜在的错误,或者您可以尝试的事情。
您的 tcl 脚本本身无法正确导入teapot
,或者 tcl 脚本和 python 脚本之间的某种交互无法正常工作,或者subprocess.Popen
无法从您的路径中正确找到teapot
包。
我会尝试按该顺序调试您的程序。 首先确认你的 tcl 脚本在不使用 python 或subprocess.Popen
的情况下工作,直接从命令行运行它(例如, C:\Users\blah tclsh tcltest.tcl
)
然后,在您确保您的脚本工作后,引入 Python。 从我所看到的,你对 python 的东西没有任何问题,但是你的 tcl 脚本或者你的路径有一些问题。
subprocess.Popen
的重点是标准通道的重定向,因此您可以以编程方式处理输出,而不是在您自己的标准输出中看到它。 你试过处理它吗? 如何?
也许您根本不需要重定向:那么os.system("tclsh tcltest.tcl")
就足够了。 或者subprocess.Popen
可能对您有其他优势——然后弄清楚如何禁用重定向,或者如何将孩子的标准输出重定向到您自己的标准输出。
我想我可能有适合你的解决方案。 或者至少尝试一种不同的方法。 此示例将 TCL shell 作为进程打开。 然后你向它发送命令,就好像你在命令行上一样。 既然你说你的命令行有效,我想这也行。 这适用于使用 Python 3.7.6 和 TCL 8.5 的 Windows。
需要有一点诡计。 我找到了需要线程和各种其他开销才能完成这项工作的解决方案,但它们只是失败了。 我想出的是简单和同步的。
stdout.readline() 会阻塞。 所以如果你的 TCL 命令没有返回任何东西,你就完蛋了。
因此,您可以通过附加一个无害的 TCL puts 命令来强制返回一些内容,该命令会与 Python 脚本进行通信,告知工作已完成。
另一个技巧是您需要“puts []”命令以强制将输出返回到标准输出。
如果您需要获取更多 TCL 文件的源代码,那么在您最终调用要运行的内容之前添加这些文件。 无论您需要在 cli 上做什么,都可以通过此过程完成。
我的代码将这一切都包装在一个带有方法的类中。 为了这个例子,我把它们全部放在一起。 在调试时保留 errorInfo 代码,并根据需要删除。
注意:您还可以使用 TCL“info body”将脚本读入字符串变量,然后在整个过程中运行每一行。 本质上,如果在 Python 调试会话中,单步执行 TCL。 抱歉,这不太管用。 注释的变通方法不适用于左花括号。
希望这可以帮助那里的人。
编辑:使用多行字符串处理注释行。
import subprocess
print("------")
shell_path = r"<YOUR PATH TO THE TCL INTERPRETER SHELL>"
tcl_shell = subprocess.Popen(shell_path,
stdin =subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines = True,
bufsize = 0)
#
# Use ONE of the "command"s below. I have them here in series for exmaples.
#
# Simple
command = r"set temp 5"
# Multiline with error --> This will give an error of course to see the error extraction in action
command = r"""
set temp 5
set temp2 [expr temp + 5]
"""
# Multiline working
command = r"""
set temp 5
set temp2 [expr $temp + 5]
"""
# More output
command = r"""
puts "Starting process"
set temp 5
puts $temp
set temp2 [expr $temp + 5]
"""
# Comments handled
command = r"# comment!"
# Be sure to leave the newline to handle comments
tcl_shell.stdin.write(f"""puts [{command}
] \nputs \"tcl_shell_cmd_complete\"\n""")
# NOTE: tcl_shell.stdin.flush() does not seem to be needed. Consider if needed.
result = ""
line = tcl_shell.stdout.readline()
while line != "tcl_shell_cmd_complete\n":
result += line
line = tcl_shell.stdout.readline()
print(f"tcl_shell sent:\n{command}")
print(f"tcl_shell result:\n{result}".rstrip())
command_error_check = "puts $errorInfo"
tcl_shell.stdin.write(f"{command_error_check} \nputs \"tcl_shell_cmd_complete\"\n")
resultErr = ""
line = tcl_shell.stdout.readline()
while line != "tcl_shell_cmd_complete\n":
resultErr += line
line = tcl_shell.stdout.readline()
print(f"tcl_shell error info:\n{resultErr}")
tcl_shell.stdin.close()
tcl_shell.terminate()
tcl_shell.wait(timeout=0.5)
print("------")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.