python上传文件到Linux&从Linux下载文件&在Linux执行命令

python上传文件到Linux&从Linux下载文件&在Linux执行命令

直接上代码

import os.path
import stat
from pathlib import PurePosixPath
from typing import Dict

from paramiko.client import SSHClient, AutoAddPolicy
from paramiko.sftp_attr import SFTPAttributes
from paramiko.sftp_client import SFTPClient


class SSH:
    def __init__(self, ip: str, port: int, username: str, password: str, timeout: int):
        self.ip = ip
        self.port = port
        self.username = username
        self.password = password
        self.timeout = timeout
        self.client = SSHClient()
        self._conn = False
        self.sftp: [SFTPClient, None] = None

    def conn(self):
        ip = self.ip
        port = self.port
        username = self.username
        timeout = self.timeout
        password = self.password
        self.client.set_missing_host_key_policy(AutoAddPolicy())
        self.client.connect(ip, port, username, password=password, timeout=timeout)
        self._conn = True

    def close(self):
        if self.sftp:
            self.sftp.close()
        if self._conn:
            self.client.close()

    def exec_cmd(self, cmd: str):
        if not self._conn:
            self.conn()
        _, out, err = self.client.exec_command(cmd)
        out = out.read().decode()
        err = err.read().decode()
        return out, err

    def activation_sftp(self):
        self.sftp = SFTPClient.from_transport(self.client.get_transport())

    def download_file(self, download_info: Dict[str, str]):
        # local_path 必须拼接到文件名
        if not self.sftp:
            self.activation_sftp()
        sftp: SFTPClient = self.sftp

        for k in download_info:
            path = PurePosixPath(k)
            ret: SFTPAttributes = sftp.stat(str(path))
            mode = ret.st_mode
            is_file = stat.S_ISREG(mode)
            assert is_file, f'远程路径不是一个文件:{path}'

        for k, v in download_info.items():
            v = os.path.abspath(v)
            if not os.path.exists(os.path.dirname(v)):
                os.makedirs(os.path.dirname(v))
            sftp.get(k, v)

    def upload_file(self, upload_info: Dict[str, str]):
        """
        :param upload_info: 上传的字典 key是本地的文件 value是远程Linux的路径 必须写到具体文件名
        :return:
        """
        for k in upload_info:
            path = os.path.abspath(k)
            assert os.path.isfile(path), "本地源文件不存在"

        if not self.sftp:
            self.activation_sftp()
        sftp: SFTPClient = self.sftp
        for k, v in upload_info.items():
            k = os.path.abspath(k)
            v = PurePosixPath(v)
            suffix = v.suffix
            assert suffix, "保存路径必须具体到文件名"
            print(f"upload {k} ===> {v}")
            self.exec_cmd(f'mkdir -p {v.parent}')  # 创建文件夹
            ret = sftp.put(k, str(v))  # 会覆盖已有的文件
            print(f"upload ret:{ret}")


def main():
    obj = SSH("172.17.140.17", 22, "root", "abc123", 60)
    obj.conn()
    out, err = obj.exec_cmd("df -h")  # 执行命令
    print(f'out:{out}')
    print(f"err:{err}")
    print()
    out, err = obj.exec_cmd("free -h")  # 执行命令
    print(f'out:{out}')
    print(f"err:{err}")
    print()

    path = "/tmp/tmp1/my_tar.tar.gz"
    p = PurePosixPath(path)  # 声明这个是Linux路径
    obj.exec_cmd(f'mkdir -p {p.parent}')  # 创建文件夹
    out, err = obj.exec_cmd(f"tar cfvzP {path} /home/tmp/data")  # 压缩文件夹
    print(f'out:{out}')
    print(f"err:{err}")

    upload_info = {
        "a.txt": "/tmp/aaa/a.txt",  # 目标路径必须是文件名 而不能是文件夹
        "b.txt": "/tmp/aaa/b.txt"  # 目标路径必须是文件名 而不能是文件夹
    }
    obj.upload_file(upload_info)

    download_info = {
        "/tmp/aaa/a.txt": "a.txt",  # 源路径必须是个文件
        "/tmp/aaa/b.txt": "cc/vv/a"  # 源路径必须是个文件
    }
    obj.download_file(download_info)

    obj.close()


if __name__ == '__main__':
    main()

解析

  • 通过SSHClient()创建SSH客户端
  • 通过self.client.connect连接到Linux
  • 通过SFTPClient.from_transport(self.client.get_transport())创建sftp客户端
  • 上传时会在Linux自动创建文件夹
  • 下载时先判断Linux中是否存在要下载的文件
  • 目前只支持上传和下载文件
posted @ 2023-09-13 11:22  南风丶轻语  阅读(265)  评论(0编辑  收藏  举报