从Python运行命令,然后关闭

问题描述:

我想构建一个小的shell应用程序,它从GUI应用程序运行一个命令。当我按下“关闭”按钮时,该命令的控制台应该关闭。我有两个问题:从Python运行命令,然后关闭

  1. 当我运行该命令时,该命令在与我的Python脚本相同的控制台上运行。我如何在新的控制台中打开命令?

  2. 如何停止命令?我的意思是,如果该命令与GUI的工作过程相同,我可以使用exit(),但是整个程序将终止。

这是我到目前为止的代码:

from tkinter import * 
import subprocess 
import os 

top = Tk() 

def turnOn(): 
    p = subprocess.Popen("ping *.com") 

def turnOff(): 
    pass 
    #should i do: p.close() of something? 

on = Button(top, text = "on", command = turnOn) 
off = Button(top, text = "off", command = turnOff) 

on.grid() 
off.grid() 
top.mainloop() 
+0

你有没有尝试cmd的选项,例如''cmd/c“ping *.com”''? – Gribouillis

+0

最初的问题与控制台混淆了CMD。我没有看到任何与CMD外壳相关的东西,所以我编辑它来专注于控制台。使用参数'creationflags = subprocess.CREATE_NEW_CONSOLE'可以很容易地获得一个新的控制台。 – eryksun

您可以通过调用子进程的.terminate方法停止命令。下面是一个粗略的例子,它使用全局变量来存储Popen对象;将GUI包装在一个类中会更好,并将proc作为该类的实例属性存储。

import tkinter as tk 
import subprocess 

top = tk.Tk() 

proc = None 

def turnOn(): 
    global proc 
    if proc is None: 
     print('Starting ping') 
     proc = subprocess.Popen(["ping", "example.com"]) 

def turnOff(): 
    global proc 
    if proc is not None: 
     print('Stopping ping') 
     proc.terminate() 
     proc = None 

on = tk.Button(top, text = "on", command = turnOn) 
off = tk.Button(top, text = "off", command = turnOff) 

on.grid() 
off.grid() 

top.mainloop() 

if proc is None:线防止ping命令被重新启动,如果它已经运行。

+0

是的,但如果我在新控制台中执行命令,如:subprocess.Popen(command,creationflags = subprocess.CREATE_NEW_CONSOLE),则proc.terminate()将不会关闭新控制台。 – odri

+0

@odri好的。 (我无法测试,因为我不使用Windows)。但为什么你真的需要在新的控制台上运行? –

1)当我运行命令时,cmd命令运行在与我的 pythoh脚本工作相同的cmd上。我怎样才能打开另一个cmd窗口中的命令?

我假设您试图说您需要在另一个 shell上运行该进程。您应该使用的子功能的“壳”参数:

subprocess.call(cmd, shell=True) 

相反,如果你只需要另一个命令提示符窗口,只是POPEN另一个Windows CMD。

2)如何停止命令?我的意思是,如果命令是在同一个 窗口上工作的,我可以在exit()中使用gui工作,但是所有程序将会停止。

子过程Popen对象有一个终止方法。你可以调用这个发送一个SIGTERM信号,但并不总是可靠的。因此,有从您的操作系统和您的过程 的性质取决于几个选项(一张小纸条:POPEN对象与进程的PID一个PID属性):

  • os.kill(PID,信号) =>杀上的Posix/Windows操作系统
  • os.killpg(PGID,信号) =>一个简单的过程杀死一个进程作为在Unix操作系统
  • 子的基团。POPEN( “TASKKILL/F/T/PID%i” 的%PID,壳=真) =>杀上的窗口的处理

信号是从OS根据一个POSIX /窗口信号。即:

os.killpg(self.pid, signal.SIGKILL)  # Posix 
os.kill(self.pid, signal.CTRL_C_EVENT) # Windows 

os.kill调用在Windows上并不总是可靠的。这是使用第三个选项的原因 。

+1

CMD不是控制台;它执行REPL就像python.exe在交互式运行时一样。命令行shell或REPL从标准输入读取并写入标准输出和标准错误。它没有实现它们,它不知道任何有关窗口,窗口消息,鼠标输入等。产生一个新的cmd.exe实例继承当前的控制台。要创建一个新的控制台(即conhost.exe的实例),请使用创建标志CREATE_NEW_CONSOLE。除非需要运行批处理文件或使其执行命令行,否则CMD不涉及此问题。 – eryksun

+0

Windows没有信号。 Python在Windows上的'os.kill()'实现是一个混合函数。在一个层面上,它就像'os.killpg'一样。如果您连接到与子进程相同的控制台,并且您使用'CREATE_NEW_PROCESS_GROUP'创建了进程,即其进程ID也是进程组ID,则可以向其发送控制台控制事件,即'CTRL_C_EVENT'(0 )或'CTRL_BREAK_EVENT'(1),但Ctrl + C默认是禁用的,所以只有Ctrl + Break是可靠的。这称为WinAPI'GenerateConsoleCtrlEvent'。传递不是进程组ID的ID是未定义的行为。 – eryksun

+0

将控件事件发送到进程组0将事件广播到连接到控制台的所有进程,包括您自己的进程。 – eryksun