You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python subprocess调用tcscid.exe仅返回stderr,无法获取stdout?

问题

我想用Python自动化Scid vs PC国际象棋软件的操作,该软件有命令行版本tcscid.exe。我用Python的subprocess模块调用它,代码如下:

import subprocess

process = subprocess.Popen(["C:\\Scid vs PC-4.21\\bin\\tcscid.exe"],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

command = 'sc_base create myfile'
process.stdin.write(command)
process.stdin.flush() 

#add more commands

output, error = process.communicate()

print("STDOUT output:")
print(output)

print("STDERR output:")
print(error)

现在遇到两个核心问题:

  • 需要在每条命令执行后检查错误,但不关闭程序时读取输出/错误流会导致代码崩溃。
  • 用communicate()也获取不到正常命令的stdout输出(手动在cmd里执行有正常输出),只有错误命令能拿到stderr信息,且命令实际是生效的(比如能成功创建文件)。

解决方案

1. 修复无stdout输出的问题

tcscid.exe是Tcl交互式程序,它需要每条命令末尾加换行符才会识别为命令输入完成,返回对应输出。修改命令写入代码:

command = 'sc_base create myfile\n'  # 末尾添加换行符\n
process.stdin.write(command)
process.stdin.flush()

手动在cmd中输入命令时按回车,本质就是输入换行符告知程序命令结束,代码必须模拟这个行为。

2. 逐条命令安全读取输出/错误

直接读取流会因阻塞导致崩溃,可通过线程分别监听stdout和stderr流,避免单线程阻塞问题。示例代码:

import subprocess
import threading
import time

def read_stream(stream, output_list):
    # 逐行读取流内容,直到流结束
    for line in iter(stream.readline, ''):
        output_list.append(line.strip())

# 启动进程,设置行缓冲配合readline读取
process = subprocess.Popen(
    ["C:\\Scid vs PC-4.21\\bin\\tcscid.exe"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    bufsize=1,
    universal_newlines=True
)

# 存储输出和错误的列表
stdout_content = []
stderr_content = []

# 启动线程监听流
stdout_thread = threading.Thread(target=read_stream, args=(process.stdout, stdout_content))
stderr_thread = threading.Thread(target=read_stream, args=(process.stderr, stderr_content))
stdout_thread.daemon = True
stderr_thread.daemon = True
stdout_thread.start()
stderr_thread.start()

# 执行第一条命令
cmd1 = 'sc_base create myfile\n'
process.stdin.write(cmd1)
process.stdin.flush()
# 等待命令执行完成(可根据实际场景调整等待时间,或判断输出内容)
time.sleep(0.5)

print("第一条命令STDOUT:", stdout_content)
print("第一条命令STDERR:", stderr_content)

# 清空列表准备执行下一条命令
stdout_content.clear()
stderr_content.clear()

# 执行第二条命令
cmd2 = 'sc_base list\n'
process.stdin.write(cmd2)
process.stdin.flush()
time.sleep(0.5)

print("第二条命令STDOUT:", stdout_content)
print("第二条命令STDERR:", stderr_content)

# 发送退出命令并关闭进程
process.stdin.write('quit\n')
process.stdin.flush()
process.wait()

说明:

  • bufsize=1设置行缓冲,让readline能及时获取输出。
  • 线程监听实现非阻塞读取,避免单线程下因一个流阻塞导致程序崩溃。

3. 更简便的替代方案:用Tcl脚本批量执行

由于tcscid.exe是Tcl程序,可编写Tcl脚本(比如cmds.tcl)批量执行命令:

sc_base create myfile
# 写入其他需要执行的命令
quit

然后用Python调用执行该脚本:

import subprocess

result = subprocess.run(
    ["C:\\Scid vs PC-4.21\\bin\\tcscid.exe", "cmds.tcl"],
    capture_output=True,
    text=True
)

print("STDOUT:", result.stdout)
print("STDERR:", result.stderr)

这种方式无需处理交互式流的阻塞问题,是tcscid.exe原生支持的批量执行方式,适合固定命令序列的场景。

内容的提问来源于stack exchange,提问作者tanler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:44:59