1

次のように、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 スクリプトを実行する方法を教えてください。

ありがとう

4

3 に答える 3

2

を使用して出力を取得するには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

この順序でプログラムをデバッグしてみます。まず、Pythonを使用せずにtclスクリプトが機能することを確認するかsubprocess.Popen、コマンドラインから直接実行します(たとえば、C:\Users\blah tclsh tcltest.tcl

次に、スクリプトが機能することを確認したら、Pythonを導入します。私が見ていることから、Pythonのものには問題はありませんが、tclスクリプトまたはパスに問題があります。

于 2013-01-10T17:57:23.327 に答える
1

の要点はsubprocess.Popen標準チャネルのリダイレクトであるため、独自の標準出力で出力を表示する代わりに、プログラムで出力を処理できます。扱ってみましたか?どのように?

たぶん、リダイレクトはまったく必要ありません。それならos.system("tclsh tcltest.tcl")十分なはずです。またはsubprocess.Popen、他の利点があるかもしれません。次に、リダイレクトを無効にする方法、または子のstdoutを自分のstdoutにリダイレクトする方法を理解します。

于 2013-01-10T17:56:52.847 に答える
0

私はあなたのための解決策を持っているかもしれないと思います. または、少なくとも別の方法を試してください。この例では、TCL シェルをプロセスとして開きます。次に、コマンドラインにいるかのようにコマンドをポンプします。コマンドラインが機能するとおっしゃっていたので、これも機能すると思います。これは、Python 3.7.6 および TCL 8.5 を搭載した Windows で機能します。

ちょっとしたトリックが必要です。この仕事を完了するためにスレッドやその他のあらゆる種類のオーバーヘッドを必要とするソリューションを見つけましたが、それらはうまくいきませんでした。私が思いついたのは、シンプルで同期的なものです。

stdout.readline() はブロックします。したがって、TCL コマンドが何も返さない場合、あなたは水に沈んでいます。

そのため、無害な TCL の puts コマンドを追加することで、何かを強制的に戻すことができます。このコマンドは、ジョブが完了したことを Python スクリプトに伝えます。

もう 1 つのトリックは、コマンドを「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("------")
于 2020-05-05T21:53:51.280 に答える