有测试问题请微信联系作者,备注来意(点击此处添加)
240
一名普通的测试打工人;专注自动化测试技术研究、实践、总结、分享、交流。
用我8年+的经历,给大家带来更多实用的干货。
人若有志,就不会在半坡停止。

【Python基础】Python中执行系统命令

常见四种方法

  • os.system()
  • os.popen()
  • subprocess.call()
  • subprocess.Popen()

os.system()

os.system(command)
调用os.system()函数后,程序会暂停执行,直到该命令执行完毕才会继续执行Python程序。

  • 优点:
    简单易用,可以快速执行简单的系统命令。
  • 缺点:
    无法获取系统命令的输出结果,也无法对命令执行过程进行控制。

os.popen()

os.popen(command [, mode [, bufsize]])

  • command是需要执行的系统命令
  • mode是读取命令输出的模式(默认为“r”)
  • bufsize是读取缓冲区的大小(默认为-1)

调用os.popen()函数后,可以通过read()、readline()、readlines()等方法来读取命令的输出结果。

  • 优点:
    可以获取系统命令的输出结果
  • 缺点:
    无法对命令执行过程进行控制,也无法获取命令的返回值。

subprocess.call()

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

  • args是需要执行的系统命令和参数,以列表的形式传入
  • stdin、stdout、stderr是分别指定命令的标准输入、标准输出和标准错误输出
  • shell为True时,可以执行shell命令。

调用subprocess.call()函数后,程序会暂停执行,直到该命令执行完毕才会继续执行Python程序。函数的返回值为命令的返回值。

  • 优点:
    可以获取系统命令的返回值
  • 缺点:
    无法对命令执行过程进行控制,也无法获取命令的输出结果。

subprocess.Popen()

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None,
                 stderr=None, preexec_fn=None, close_fds=True, shell=False,
                 cwd=None, env=None, universal_newlines=False, startupinfo=None,
                 creationflags=0)
  • args:要执行的命令及其参数,可以是字符串或序列,如果是序列,第一个元素通常是要执行的命令,后续元素是命令参数。
  • bufsize:缓冲区大小,对于标准 IO 通道,这个值默认为 -1,表示使用系统默认值。
  • executable:指定要使用的可执行文件,通常是 shell 程序。
  • stdin, stdout,stderr:表示标准输入、输出和错误的管道,可以是文件描述符或者一个文件对象。
  • preexec_fn:在子进程启动前执行的函数。
  • close_fds:是否关闭所有父进程打开的文件描述符,默认为 True。
  • shell:如果设置为 True,则将 args 参数作为一个字符串传递给 shell 进行解析,默认为 False。
  • cwd:在执行命令之前改变当前工作目录。
  • env:指定环境变量,可以是一个字典或者 None。
  • universal_newlines:如果设置为 True,则将输入和输出转换为文本模式,默认为 False 也就是二进制流模式。
  • startupinfo:指定一些 Windows 特定的属性,例如窗口大小、标准输入模式等等。
  • creationflags:可以用来控制子进程的创建方式,例如是否使用CREATE_NEW_CONSOLE 来创建控制台窗口。

调用subprocess.Popen()函数后,程序可以先执行Python程序的其他部分,而不需要等待命令执行完毕。
可以通过wait()方法等待命令执行完毕,获取命令的返回值;也可以通过communicate()方法获取命令的输出结果。

  • 优点:
    可以获取系统命令的输出结果和返回值,同时也可以对命令执行过程进行控制
  • 缺点:
    比其他三种方法复杂一些

subprocess.Popen()工具使用及封装

import logging
import os
import subprocess
import sys
import time
from tools.unit import file_path


class SubProcess:
    @classmethod
    def shell_subprocess(cls, cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE):
        return subprocess.Popen(cmd, shell=shell, stdout=stdout, stderr=stderr)

    @classmethod
    def stop_server(cls, port):
        mac_cmd = f"lsof -i tcp:{port}"
        win_cmd = f"netstat -ano | findstr {port}"
        # 判断操作系统
        os_platform = sys.platform
        # print('操作系统:', os_platform)
        # #windows 系统
        if os_platform == "win32":
            win_p = cls.shell_subprocess(win_cmd)
            for line in win_p.stdout.readlines():
                if line:
                    line = line.decode('utf8')
                    if "LISTENING" in line:
                        win_pid = line.split("LISTENING")[1].strip()
                        os.system(f"taskkill -f -pid {win_pid}")
        else:
            # unix系统
            p = cls.shell_subprocess((mac_cmd))
            for line in p.stdout.readlines():
                line = line.decode('utf8')
                if "node" in line:
                    stdoutline = line.split(" ")
                    # print(stdoutline)
                    pid = stdoutline[4]
                    os.system(f"kill {pid}")
        logging.info(f"服务{port}端口已关闭")

    @classmethod
    def start_server(cls, port, cmd, log_path):
        cls.stop_server(port)
        if not os.path.exists(log_path):
            os.mkdir(log_path)
        log_name = str(port) + '-' + time.strftime('%Y_%m_%d') + ".log"
        appium_logs_dirName = os.path.join(log_path, log_name)
        cls.shell_subprocess(cmd, shell=True, stdout=open(appium_logs_dirName, mode='a', encoding="utf8"),
                             stderr=subprocess.PIPE)
        logging.info(f"服务{port}端口已开启")


class AdbSever(SubProcess):

    @classmethod
    def run_command(cls, cmd):
        cls.shell_subprocess(cmd)

    @classmethod
    def get_command(cls, cmd):
        p = cls.shell_subprocess(cmd, shell=False)
        value = p.stdout.readline()
        return value.decode("utf-8").replace('\r\n', '')

    @classmethod
    def get_devices_list(cls):
        cmd = "adb devices"
        p = cls.shell_subprocess(cmd, shell=False)
        lists = p.stdout.readlines()
        devicesList = []
        for item in lists:
            itemStr = str(item, encoding="utf-8")
            if (itemStr.strip() == ""):
                continue
            elif (itemStr.startswith("List of")):
                continue
            elif (itemStr.find("daemon") > -1):
                continue
            else:
                infos = itemStr.split("\t")
                devicesList.append({
                    "deviceId": infos[0],
                    "type": infos[1].replace('\r\n', '')
                })
        return devicesList


class AppiumServer(SubProcess):
    @classmethod
    def stop_appium(cls, port):
        cls.stop_server(port)
        logging.info(f"appium服务{port}端口已关闭")

    @classmethod
    def start_appium(cls, port):
        """
        启动appium 服务
        :param port: 服务的端口号
        :return:
        """
        cls.stop_appium(port)
        cmd = f"appium -p {port}"
        appium_logs = file_path("logs", "appium_logs")
        cls.start_server(port, cmd, appium_logs)
        logging.info(f"appium服务{port}端口已开启")


class AllureServer(SubProcess):
    @classmethod
    def create_html(cls, path):
        # allure生成报表,并启动程序
        # logging.info(f"allure数据路径:{path}_result/")
        # logging.info(f"allure存入路径:{path}_html")
        return subprocess.call(f'allure generate {path}_result/ -o {path}_html --clean', shell=True)

    @classmethod
    def stop_allure(cls, port):
        cls.stop_server(port)
        logging.info(f"allure服务{port}端口已关闭")

    @classmethod
    def start_allure(cls, port, path):
        """
        启动Allure 服务
        :param port: 服务的端口号
        :return:
        """
        cls.stop_allure(port)
        cmd = f"allure open -h 127.0.0.1 -p {port} {path}"
        allure_logs = file_path("logs", "allure_logs")
        # logging.info(f"allure服务启动路径:{allure_logs}")
        cls.start_server(port, cmd, allure_logs)
        logging.info(f"allure服务{port}端口已开启")
posted @ 2024-02-02 14:45  三叔测试笔记  阅读(362)  评论(0编辑  收藏  举报
返回顶部 跳转底部