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

Python脚本执行完毕后无法退出Windows命令提示符求助排查

脚本执行后无法回到命令行的问题排查与修复

问题描述

编写的Python脚本功能为读取prompts.txt首行,执行一系列鼠标键盘操作后删除该行,循环最多执行10次。脚本看似运行完毕,但始终无法回到Windows命令提示符,疑似卡顿或循环异常,在cmd中运行问题依旧。原代码如下:

from pyautogui import moveTo, click, typewrite, hotkey
import time
import random
import pyperclip
import tkinter as tk
from tkinter import messagebox
from threading import Thread
import fileinput

# Open the text file and read all lines
with open('prompts.txt', 'r') as file:
    lines = file.readlines()

# Limit the number of lines to process
num_lines = min(len(lines), 10)

# Create a Tkinter window
window = tk.Tk()
window.title("Script Progress")
window.geometry("200x150")  # Set the window size

# Create a label to display the countdown
countdown_label = tk.Label(window, text="Countdown: {}".format(num_lines))
countdown_label.pack()

# Function to stop the script
def stop_script():
    if messagebox.askokcancel("Stop Script", "Are you sure you want to stop the script?"):
        window.destroy()

# Create a stop button
stop_button = tk.Button(window, text="Stop", command=stop_script, width=10, height=3)  # Set the button size
stop_button.pack()

# Function to update the countdown label
def update_countdown_label(count):
    countdown_label.config(text="Countdown: {}".format(count))

# Function to perform the script logic
def run_script():
    # Loop until the counter reaches the specified number of lines or window is closed
    for i in range(num_lines):
        # Check if window is closed
        if not window.winfo_exists():
            break

        # Left click inside the text field
        click(405, 995, 1, 1, 'left')

        # Generate random sleep duration between 1 and 10 seconds
        sleep_duration = random.uniform(3, 8)

        # Wait for the message to be sent
        time.sleep(sleep_duration)

        # Type / to get prompt
        typewrite('/', interval=0.2)

        # Generate random sleep duration between 1 and 10 seconds
        sleep_duration = random.uniform(5, 10)

        # Wait for the message to be sent
        time.sleep(sleep_duration)

        # Press enter
        typewrite(['enter'])

        # Generate random sleep duration between 1 and 10 seconds
        sleep_duration = random.uniform(5, 20)

        # Wait for the message to be sent
        time.sleep(sleep_duration)

        # Extract the first line and remove it from the list
        first_line = lines.pop(0).strip()

        # Remove the first line from the file
        with fileinput.input('prompts.txt', inplace=True) as file:
            for line in file:
                if line.strip() != first_line:
                    print(line, end='')

        # Copy the first line to the clipboard
        pyperclip.copy(first_line)

        # Paste text from clipboard
        hotkey('ctrl', 'v')

        # Generate random sleep duration between 1 and 10 seconds
        sleep_duration = random.uniform(5, 20)

        # Wait for the message to be sent
        time.sleep(sleep_duration)

        # Press enter
        typewrite(['enter'])

        # Update the countdown label
        update_countdown_label(num_lines - i - 1)

    # Close the window when the script is finished
    window.destroy()

# Run the script logic in a separate thread
script_thread = Thread(target=run_script)
script_thread.start()

# Set window attributes for focus and stay on top
window.lift()
window.attributes('-topmost', True)

# Start the Tkinter event loop
window.mainloop()

注:原脚本缺少fileinput模块导入,已补充。

问题根源

  1. 非主线程操作Tkinter组件:update_countdown_label在脚本线程中直接修改UI元素,违反了Tkinter必须在主线程处理UI操作的规则,会导致事件循环紊乱,引发卡顿或死锁。
  2. 文件删除逻辑缺陷:使用fileinput的inplace=True时,通过line.strip() != first_line判断会删除所有内容匹配的行,而非仅文件的首行,若文件存在重复行会破坏数据,同时频繁IO操作可能引发阻塞。
  3. 线程收尾不彻底:脚本线程结束后销毁窗口,但主线程的mainloop可能因异常状态无法正常退出,导致进程残留,无法回到命令提示符。

修复后的代码

from pyautogui import click, typewrite, hotkey
import time
import random
import pyperclip
import tkinter as tk
from tkinter import messagebox
from threading import Thread

# Open the text file and read all lines
with open('prompts.txt', 'r') as file:
    lines = [line.rstrip('\n') for line in file]

# Limit the number of lines to process
num_lines = min(len(lines), 10)

# Create a Tkinter window
window = tk.Tk()
window.title("Script Progress")
window.geometry("200x150")

# Create a label to display the countdown
countdown_label = tk.Label(window, text=f"Countdown: {num_lines}")
countdown_label.pack(pady=20)

# Function to stop the script
def stop_script():
    if messagebox.askokcancel("Stop Script", "Are you sure you want to stop the script?"):
        window.destroy()

# Create a stop button
stop_button = tk.Button(window, text="Stop", command=stop_script, width=10, height=2)
stop_button.pack()

# Function to update the countdown label (must run in main thread)
def update_countdown_label(count):
    def safe_update():
        if window.winfo_exists():
            countdown_label.config(text=f"Countdown: {count}")
    # Use after to schedule UI update in main thread
    window.after(0, safe_update)

# Function to remove first line from file correctly
def remove_first_line():
    with open('prompts.txt', 'r') as f:
        all_lines = f.readlines()
    if len(all_lines) > 0:
        with open('prompts.txt', 'w') as f:
            f.writelines(all_lines[1:])

# Function to perform the script logic
def run_script():
    try:
        for i in range(num_lines):
            if not window.winfo_exists():
                break

            # Left click inside the text field
            click(405, 995, 1, 1, 'left')
            time.sleep(random.uniform(3, 8))

            # Type / to get prompt
            typewrite('/', interval=0.2)
            time.sleep(random.uniform(5, 10))

            # Press enter
            typewrite(['enter'])
            time.sleep(random.uniform(5, 20))

            # Extract the first line and remove it from the list
            if not lines:
                break
            first_line = lines.pop(0)

            # Remove first line from file
            remove_first_line()

            # Copy and paste text
            pyperclip.copy(first_line)
            hotkey('ctrl', 'v')
            time.sleep(random.uniform(5, 20))

            # Press enter
            typewrite(['enter'])

            # Update countdown in safe way
            update_countdown_label(num_lines - i - 1)
    finally:
        # Ensure window is closed even if exception occurs
        if window.winfo_exists():
            window.after(0, window.destroy)

# Set thread as daemon so it exits when main thread exits
script_thread = Thread(target=run_script, daemon=True)
script_thread.start()

# Set window attributes
window.lift()
window.attributes('-topmost', True)

# Start the Tkinter event loop
window.mainloop()

修复说明

  • UI操作线程安全:通过window.after将UI更新调度到主线程执行,避免跨线程操作Tkinter组件的问题。
  • 文件删除逻辑修正:重写文件时直接跳过首行,确保只删除文件的第一行,避免重复行误删。
  • 线程守护与异常处理:将脚本线程设为守护线程,确保主线程退出时子线程也随之结束;添加try-finally块保证窗口能正常销毁,避免进程残留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:22:08