首页 > 系统相关 >python控制windows命令行程序

python控制windows命令行程序

时间:2024-03-06 20:22:16浏览次数:26  
标签:输出 last python cmd windows buffer 命令行 prompt line

有一些现成的库, 比如WExpect, 是开源的, 在github上可以搜索到. 但是, 不知道为什么, 在我自己的笔记本上不能正常工作. 而其源码也比较多, 懒得定位了.
于是自己实现了一个, 用法如下.

  • 启动和停止命令行
import my_cmd as cmd
cmd.start()
cmd.stop()
  • prompt命令行提示符匹配字符串
import my_cmd as cmd
print(cmd.get_prompt())  # 输出: `[A-Za-z]:\\.*>$`
# cmd.set_prompt('>')  # 设置提示符匹配字符串, 需要是正则表达式
  • 轮询等待expect预期输出
    功能: 轮询等待expect预期输出, 如果没有预期输出, 则一直等待下去.
    原型: expect(*regex_infos:str)->int:
    expect(): 如果不用参数, 则默认等待prompt提示符出现.
    如果参数有一个或者多个正则表达式, 则返回第一个匹配的正则表达式在列表中的索引. 如果匹配到prompt, 则返回0.
import my_cmd as cmd
cmd.start()
cmd.expect()
cmd.stop()

输出:

Microsoft Windows [版本 10.0.22621.3155]
(c) Microsoft Corporation。保留所有权利。

d:\MyCode\Libs\Python\Test\my_cmd>
cmd.exe process exited.
  • 查看和清除输出
import my_cmd as cmd
cmd.start()
cmd.expect()
print(cmd.get_output())  # 获取所有的输出
print(cmd.get_last_line())  # 获取最后一行的输出
print(cmd.clear_output())  # 清除输出信息
cmd.stop()
  • 输入命令
    write_line(cmd:str): 输入命令, 自动添加换行符. 为防止输出信息干扰, 会先清除之前的输出信息.
import my_cmd as cmd
cmd.start()
cmd.expect()
cmd.write_line('pwd')
cmd.expect()
cmd.stop()

输出:

Microsoft Windows [版本 10.0.22621.3155]
(c) Microsoft Corporation。保留所有权利。

d:\MyCode\Libs\Python\Test\my_cmd>pwd
/d/MyCode/Libs/Python/Test/my_cmd

d:\MyCode\Libs\Python\Test\my_cmd>
cmd.exe process exited.

源代码

import Common
import io
import re
import time
import subprocess

# region 全局变量
_buffer = io.StringIO()
'''存放输出字符串的缓冲区'''
_last_line_buffer = io.StringIO()
'''最后一行的输出缓冲区. 主要是为了提高expect函数的匹配效率.'''
_proc:subprocess.Popen = None
'''cmd.exe进程对象'''
_prompt:str = r'[A-Za-z]:\\.*>$'  # 有时候盘符也可能是小写
r'''默认提示信息. 形如: C:\Users\huzho>'''
# endregion

def clear_output() -> None:
    '''清除输出'''
    global _buffer,_last_line_buffer
    _buffer.close()
    _buffer = io.StringIO()
    _last_line_buffer.close()
    _last_line_buffer = io.StringIO()

def expect(*regex_infos:str)->int:
    '''
    等待预期的字符串出现. 为提高效率, 默认只匹配输出的最后一行.
    返回值: 匹配到的预期字符串的索引, 如果为0, 表示prompt, 其余的按顺序为1,2,3...
    '''
    regex_infos = list(regex_infos)
    regex_infos.insert(0, _prompt)  # 增加上提示符
    while True:  # 循环匹配, 直到匹配成功为止
        for i,reg_info in enumerate(regex_infos):
            if re.search(reg_info, get_last_line()):
                return i
        time.sleep(0.1)  # 防止死循环

def get_last_line() -> str:
    '''获取输出的最后一行字符串'''
    return _last_line_buffer.getvalue()

def get_output() -> str:
    '''获取当前的输出'''
    return _buffer.getvalue()

def get_prompt() -> str:
    '''获取当前的提示符'''
    return _prompt

@Common.run_in_thread
def _output():
    '''轮询输出'''
    global _last_line_buffer
    while True:
        output = _proc.stdout.read(1)  # 读取一个字符, 保证了只要有输出, 就会及时响应
        if output == '' and _proc.poll() is not None:   # poll函数有值, 表示进程已退出
            _buffer.close()  # 清空缓冲区
            _last_line_buffer.close()
            print('cmd.exe process exited.')
            break
        print(output,end='')
        _buffer.write(output)  # 写入缓冲区中
        # 处理最后一行的缓冲区
        if output == '\n':  # 如果换行, 则重置最后一行
            _last_line_buffer.close()
            _last_line_buffer = io.StringIO()
        else:
            _last_line_buffer.write(output)

def set_prompt(prompt:str) -> None:
    '''设置提示符'''
    global _prompt
    _prompt = prompt

def start():
    '''启动cmd进程并轮询输出'''
    global _proc,_buffer,_last_line_buffer
    _buffer = io.StringIO()
    _last_line_buffer = io.StringIO()
    
    _proc = subprocess.Popen('cmd.exe', 
                            stdin=subprocess.PIPE, 
                            stdout=subprocess.PIPE, 
                            #stderr=subprocess.PIPE, 
                            stderr=subprocess.STDOUT,  # 错误信息也同时输出
                            #encoding='gbk',  # windows下的编码, 可以打印汉字信息, 是不是`text=True`就可以了?
                            cwd=None,  # 工作目录, 后续可以增加设置工作目录的功能
                            bufsize=1,
                            text=True)
    _output()  # 在另一个线程中轮询输出

def stop():
    '''停止cmd进程'''
    #send('exit')
    _proc.terminate()
    

def write_line(line:str) -> None:
    '''写入命令. 写入命令之前先清除之前的输出. 以免有干扰.'''
    clear_output()  # 先清除之前的输出
    _proc.stdin.write(line + '\n')
    _proc.stdin.flush()

BTW: 虽然主要是针对windows系统的, 但是改造一下, 应该也可以用于linux系统, 因为是纯python语言开发的.

标签:输出,last,python,cmd,windows,buffer,命令行,prompt,line
From: https://www.cnblogs.com/huzhongqiang/p/18057198

相关文章

  • 08Windows系统安装的准备工作2
    Windows系统安装的准备工作2安装虚拟机VMWareWorkStation17Pro虚拟机是一种能够模拟真正电脑的各种软硬件的软件.在对操作系统的安装不明了清晰的情况下,虚拟机是一个做实验的极佳的工具和平台.在虚拟机软件里,你可以把自己的所有操作当做在真正的电脑上一样.拥有一款虚拟机......
  • Python中那些简单又好用的特性和用法
    Python作为我的主力语言帮助我开发了许多DevOps运维自动化系统,这篇文章总结几个我在编写Python代码过程中用到的几个简单又好用的特性和用法,这些特性和用法可以帮助我们更高效地编写Python代码1.链式比较x=5y=10z=15ifx<y<z:print("xislessthanyandy......
  • qgis 3.30 python开发环境搭建
     1.使用mamba加速conda下载qgiscondainstall-cconda-forge-nbasemamba2.创建qgis虚拟环境condacreate-nqgispython=3.11condaactivateqgis(管理员CMD)mambainstall-cconda-forgeqgis=3.30.0mambainstall-cconda-forgerasteriomambainstall-cco......
  • 【Python基础】Python 函数返回多个值和函数注解
    [本文出自天外归云的博客园]Python函数返回多个值和函数注解在Python中,函数可以返回多个值。这在某些情况下很有用,因为它允许函数一次性返回多个相关联的结果。Python使用元组(tuple)来实现这一特性。函数返回多个值示例下面是一个示例函数,它接受一个整数和一个字符串作为......
  • Python涉及路径相关的知识点
    脚本中的路径信息print('__file__:',__file__)#脚本的位置print('os.path.abspath(__file__)::',__file__)#脚本的绝对路径(和上面的一般情况下是一样的)print('os.path.abspath(__file__):',os.path.abspath(__file__))SCRIPT_DIR=os.path.dirname(os.path.abspat......
  • Python list列表pop弹出内容del移除内容结果不对错误
    前言全局说明Pythonlist列表pop弹出内容del移除内容结果不对一、功能需求一个list列表,内容是1-9,用for循环打印,打印过的值,从列表中删除二、输出结果不对,代码有问题文件名:test.py#!/usr/bin/envpython3#coding:UTF-8#-*-coding:UTF-8-*-lists_1=['a','b']......
  • Python函数每日一讲 - hex()
    引言在Python编程中,处理十六进制数据是一项常见的任务。hex()函数就是Python中用于将整数转换为十六进制字符串的函数。本文将深入介绍hex()函数的使用方法,并通过实例演示其在实际应用中的作用,帮助大家更好地掌握这一工具。语句概览hex()函数是Python内置函数之一,用于将整数转......
  • Pycharm的安装以及如何跳过试用设置永久使用?(Windows专业版2023-2024)
    目录一.Pycharm安装包下载二.Pycharm安装包安装三.设置永久使用一.Pycharm安装包下载官网下载(较慢),直接点击Download即可。也可以直接使用baidu网盘下载Pycharm官网地址Pycharm安装包网盘下载(内含安装视频及pojie包)二.Pycharm安装包安装直接双击第一步下载的安装......
  • Python-动态类型
    动态类型在Python中,类型是在运行时自动确定的,而不是通过代码声明,即Python没有必要事先声明变量。1.变量、对象和引用变量创建:一个变量在代码第一次给它赋值时就创建了它,之后的赋值将会改变已创建的变量的值;Python在代码运行之前会先检测变量名,是最初的赋值操作在创建变量。变......
  • VMware中的Ubuntu虚拟机中实现与windows宿主机的复制粘贴互通
    背景如果经常需要用到虚拟机的话,就肯定需要虚拟机和宿主机之前能够任意的交换数据,能够方便的无障碍复制粘贴以前用windows虚拟机的时候,可以通过安装VMwareTools实现但是在使用ubuntu桌面版式,发现,无法安装VMwareTools或者虽然通过其他方法安装了也还是无法做到无障碍的......