Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过python按子流程运行TCL,但不提供任何输出_Python_Tkinter_Tcl_Eval_Subprocess - Fatal编程技术网

通过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

我正在尝试通过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>
给了我这个错误

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("------")