通过python按子流程运行TCL,但不提供任何输出
我正在尝试通过python子流程运行我的tcl脚本,如下所示:通过python按子流程运行TCL,但不提供任何输出,python,tkinter,tcl,eval,subprocess,Python,Tkinter,Tcl,Eval,Subprocess,我正在尝试通过python子流程运行我的tcl脚本,如下所示: import subprocess >>> subprocess.Popen(["tclsh", "tcltest.tcl"]) <subprocess.Popen object at 0x0000000001DD4DD8> >>> subprocess.Popen(["tclsh", "tcltest.tcl"], shell=True ) <subprocess.Popen
import subprocess
>>> subprocess.Popen(["tclsh", "tcltest.tcl"])
<subprocess.Popen object at 0x0000000001DD4DD8>
>>> subprocess.Popen(["tclsh", "tcltest.tcl"], shell=True )
<subprocess.Popen object at 0x0000000002B34550>
给了我这个错误
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"
导入TCLCall
>>>TCLCall.TCLRun()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TCLCall.TCLRun()
文件“C:\Users\XXX\Desktop\PKT\TCLCall.py”,第24行,在TCLRun中
root.tk.call('eval',tcl\u脚本)
Tcl错误:找不到名为“stdout”的频道
这就是我切换到子流程的原因。至少它没有给我错误
你知道如何通过python运行我的tcl脚本和内部必需的包吗
谢谢subprocess.Popen的整个要点是重定向标准通道,因此您可以通过编程方式处理输出,而不必在自己的标准输出上看到它。你试过处理它吗?怎么做
也许您根本不需要重定向:那么
os.system(“tclsh tcltest.tcl”)
就足够了。或者可能subprocess.Popen
对您还有其他好处--然后找出如何禁用重定向,或者如何将子进程的stdout重定向到您自己的stdout。要使用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脚本之间的某种交互工作不正常,或者子进程。Popen
无法从您的路径正确找到teapot
包
我会试着按那个顺序调试你的程序。首先确认tcl脚本在不使用python或subprocess.Popen
的情况下工作,并直接从命令行运行它(例如,C:\Users\blah tclsh tcltest.tcl
)
然后,在确保脚本正常工作后,引入Python。据我所见,python的东西没有任何问题,但是tcl脚本或路径有问题。我想我可能有一个解决方案。或者至少尝试一种不同的方法。此示例将TCL shell作为一个进程打开。然后,您可以像在命令行上一样向它发送命令。既然你说你的命令行可以工作,我想这也可以。这对我来说适用于使用Python 3.7.6和TCL 8.5的Windows
需要有点小把戏。我已经找到了一些解决方案,这些解决方案需要线程和其他各种开销来完成这项工作,但这些解决方案都失败了。我想到的是简单和同步的
readline()将被阻止。因此,如果您的TCL命令没有扔回任何东西,您就死在水里了
因此,通过附加一个无害的TCL-puts命令,强制返回一些内容,该命令向Python脚本返回任务完成的消息
另一个技巧是,您需要“放入[]”命令以强制将输出返回到stdout
如果您需要获取更多的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("------")
导入子流程
打印(“----”)
shell_路径=r“”
tcl_shell=subprocess.Popen(shell_路径,
stdin=子流程.PIPE,
stdout=子流程.PIPE,
stderr=子流程.PIPE,
universal_newlines=True,
bufsize=0)
#
#使用下面的“命令”之一。我在这里为Exmaple系列制作了它们。
#
#简单的
命令=r“设置温度5”
#带错误的多行-->这当然会给出一个错误,以查看正在进行的错误提取
命令=r“”
设定温度5
设置温度2[expr temp+5]
"""
#多线加工
命令=r“”
设定温度5
设置temp2[expr$temp+5]
"""
#更多输出
命令=r“”
将“启动过程”置于
设定温度5
把$temp
设置temp2[expr$temp+5]
"""
#处理的意见
命令=r“#注释!”
#一定要留下新行来处理注释
tcl_shell.stdin.write(f“”)放置[{command}
]\nputs \“tcl\u shell\u cmd\u complete \“\n”“”)
#注意:似乎不需要tcl_shell.stdin.flush()。如果需要的话考虑。
result=“”
line=tcl_shell.stdout.readline()
在线时!=“tcl\u shell\u cmd\u complete\n”:
结果+=行
line=tcl_shell.stdout.readline()
打印(f“tcl_shell已发送:\n{command}”)
打印(f“tcl_shell结果:\n{result}”.rstrip())
命令\u error\u check=“放置$errorInfo”
写入(f“{command\u error\u check}\nputs\”tcl\u shell\u cmd\u complete\”\n)
resulter=“”
line=tcl_shell.stdout.readline()
在线时!=“tcl\u shell\u cmd\u complete\n”:
resultErr+=行
line=tcl_shell.stdout.readline()
打印(f“tcl_外壳错误信息:\n{resulter}”)
tcl_shell.stdin.close()
tcl_shell.terminate()
tcl_shell.wait(超时=0.5)
打印(“----”)
谢谢,os.system(“tclsh tcltest.tcl”)回溯(最近一次调用):os.system(“tclsh tcltest.tcl”)名称中第1行的文件“”。错误:名称“os”未定义您必须导入os
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("------")