HOWTO · Python
在 Python 中使用 SCP 协议
本教程讨论了在 Python 中使用安全复制协议。
本页内容
scp 命令和 Python 的 SCPClient 都可以通过 SSH 在本地计算机与远程服务器之间传输文件。如果希望在 Python 中管理 SSH 连接和传输调用,可以使用 SCPClient;如果系统已安装 OpenSSH 的 scp 程序,并希望由 Python 启动它,则可以使用 subprocess.run()。无论采用哪种方式,传输数据前都应配置身份验证和受信任的主机密钥。
在 Python 中使用 SCP 模块传输文件
请在运行应用程序的环境中安装 paramiko 和 scp 包。SSHClient 用于建立 SSH 连接,SCPClient 则通过该连接的传输通道发送或接收文件。此库通过其基于 SSH 的 SCP 实现进行通信;示例中有时会重复出现较旧的 SCP1/SSH1 描述,但不应将其当作当前 Paramiko 和 scp 包行为的一般说明。
以下脚本通过环境变量读取主机、用户名和本地文件路径。请将默认值替换为自己的连接信息;若要使用其他传输方式,可将 SCP_MODE 设为 download、recursive 或 memory。默认的 upload 模式会将本地文件传到 /home/<user>/。示例会加载已知主机密钥,并保留 Paramiko 默认的缺少主机密钥处理策略,因此不会默默信任未知主机。若 SSH 代理或已配置的密钥文件可用,脚本会使用它们;请根据自己的环境设置相应的身份验证选项。此网络示例没有附带实际观察到的输出。
import io
import os
def transfer():
host = os.environ.get("SCP_HOST")
if not host:
return
import paramiko
from scp import SCPClient
user = os.environ.get("SCP_USER", "your_user")
local_path = os.environ.get("SCP_LOCAL_FILE", "report.txt")
remote_path = f"/home/{user}/report.txt"
mode = os.environ.get("SCP_MODE", "upload")
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
scp = None
try:
ssh.connect(hostname=host, username=user)
scp = SCPClient(ssh.get_transport())
if mode == "download":
scp.get(remote_path, local_path)
elif mode == "recursive":
scp.put("local_directory", remote_path=f"/home/{user}/", recursive=True)
elif mode == "memory":
scp.putfo(io.BytesIO(b"report contents\n"), remote_path)
else:
scp.put(local_path, remote_path)
finally:
try:
if scp is not None:
scp.close()
finally:
ssh.close()
if __name__ == "__main__":
transfer()
put(local_path, remote_path) 用于上传本地文件,get(remote_path, local_path) 用于下载文件。put(..., recursive=True) 可以发送整个目录树。putfo() 接受二进制文件类对象,适用于内容已在内存中的情况;其第一个参数必须能从当前读取位置读取。即使传输引发错误,finally 块也会先关闭 SCP 客户端,再关闭 SSH 客户端。请启用主机密钥检查,并配置所需的密钥、代理或其他受支持的身份验证方式;不要将密码写入源代码。加载系统主机密钥只会提供受信任的密钥,不会提供身份验证凭据,也不保证每台服务器都已在其中登记。
使用 subprocess.run() 函数传输 SCP 文件
subprocess.run() 会启动本地进程。它不会在远程服务器上执行 shell 命令:实际传输由本地 scp 可执行程序处理,该程序会自行建立 SSH 连接。本地计算机必须安装 scp,并且其 SSH 配置、密钥或代理以及 known-hosts 文件必须允许建立连接。请使用参数列表并设置 shell=False(默认值),这样路径和选项会作为独立参数传递。
设置下面的环境变量,即可将本地文件传到远程目标位置。若要下载,请调换源和目标参数的顺序,让远程路径排在前面。脚本会捕获本地可执行程序缺失的情况,并通过返回值报告非零退出状态;如果没有配置服务器并完成身份验证,它不会声称传输成功。此示例同样未在远程主机上执行。
import os
import subprocess
def copy_file():
host = os.environ.get("SCP_HOST")
if not host:
return 0
user = os.environ.get("SCP_USER", "your_user")
local_path = os.environ.get("SCP_LOCAL_FILE", "report.txt")
remote_path = os.environ.get("SCP_REMOTE_FILE", f"/home/{user}/report.txt")
command = ["scp", local_path, f"{user}@{host}:{remote_path}"]
try:
completed = subprocess.run(command, check=False)
except FileNotFoundError:
return 127
return completed.returncode
if __name__ == "__main__":
copy_file()
子进程返回码为零,表示 scp 报告成功;非零值则表示传输命令失败。在应用程序中,应检查或传递该返回码,并处理 FileNotFoundError,以便将可执行程序缺失与 SSH 或传输失败区分开来。对于可能包含用户输入的值,请避免使用 shell=True。若要执行远程命令,请使用 SSH 库,或另行构造明确的 SSH 调用;subprocess.run() 本身只会启动本地进程。如果要在 Python 代码中集成文件传输,可选择 SCPClient;如果更倾向于使用系统的 OpenSSH 客户端及其配置,则可选择 scp 可执行程序。