如何在 Python 中进行 scp?

Posted

技术标签:

【中文标题】如何在 Python 中进行 scp?【英文标题】:How to scp in Python? 【发布时间】:2010-09-20 00:00:51 【问题描述】:

在 Python 中 scp 文件的最 Pythonic 方式是什么?我知道的唯一路线是

os.system('scp "%s" "%s:%s"' % (localfile, remotehost, remotefile) )

这是一种 hack,在类 Linux 系统之外无法使用,需要 Pexpect 模块的帮助以避免密码提示,除非您已经为远程主机设置了无密码 SSH。

我知道 Twisted 的 conch,但我更愿意避免自己通过低级 ssh 模块实现 scp。

我知道paramiko,这是一个支持 SSH 和 SFTP 的 Python 模块;但它不支持 SCP。

背景:我正在连接一个不支持 SFTP 但支持 SSH/SCP 的路由器,所以 SFTP 不是一个选项。

编辑: 这是How to copy a file to a remote server in Python using SCP or SSH? 的副本。 但是,该问题没有给出处理 Python 内部密钥的特定于 scp 的答案。我希望有一种方法来运行类似的代码

import scp

client = scp.Client(host=host, user=user, keyfile=keyfile)
# or
client = scp.Client(host=host, user=user)
client.use_system_keys()
# or
client = scp.Client(host=host, user=user, password=password)

# and then
client.transfer('/etc/local/filename', '/etc/remote/filename')

【问题讨论】:

【参考方案1】:

如果你在 win32 上安装 putty,你会得到一个 pscp(putty scp)。

所以你也可以在 win32 上使用 os.system hack。

(您可以使用 putty-agent 进行密钥管理)


抱歉,这只是一个 hack (但你可以将它包装在 python 类中)

【讨论】:

'nix one 工作的唯一原因是,你有 SCP 在路径上;正如 Blauohr 指出的那样,这并不难解决。 +1【参考方案2】:

您可能有兴趣尝试Pexpect (source code)。这将允许您处理输入密码的交互式提示。

这是来自主网站的示例用法(用于 ftp):

# This connects to the openbsd ftp site and
# downloads the recursive directory listing.
import pexpect
child = pexpect.spawn ('ftp ftp.openbsd.org')
child.expect ('Name .*: ')
child.sendline ('anonymous')
child.expect ('Password:')
child.sendline ('noah@example.com')
child.expect ('ftp> ')
child.sendline ('cd pub')
child.expect('ftp> ')
child.sendline ('get ls-lR.gz')
child.expect('ftp> ')
child.sendline ('bye')

【讨论】:

【参考方案3】:

嗯,也许另一种选择是使用sshfs 之类的东西(Mac 也有sshfs)。安装路由器后,您可以直接复制文件。我不确定这是否适用于您的特定应用程序,但它是一个很好的解决方案,便于使用。

【讨论】:

【参考方案4】:

您也可以查看paramiko。还没有 scp 模块,但它完全支持 sftp。

[编辑] 抱歉,错过了你提到 paramiko 的那一行。 以下模块只是 paramiko 的 scp 协议的实现。 如果您不想使用 paramiko 或 conch(我所知道的用于 python 的唯一 ssh 实现),您可以重新设计它以使用管道在常规 ssh 会话中运行。

scp.py for paramiko

【讨论】:

您是说附加的解决方案可以安全地将文件传输到任何运行 sshd 的机器上,即使它没有运行 sftpd?这正是我正在寻找的东西,但我无法从您的评论中判断这是否只是将 sftp 包装在类似 scp 的外观中。 这将与任何运行 sshd 的机器传输文件,该机器在 PATH 中有 scp(scp 不是 ssh 规范的一部分,但它相当普遍)。这在服务器上调用“scp -t”,并使用scp协议传输文件,与sftp无关。 请注意,我使用 openssh 的 scp 实现作为模型,因此不保证适用于其他版本。一些版本的sshd也可能使用scp2协议,与sftp基本相同。 您能否看到这个问题:***.com/questions/20111242/… 我想知道 paramiko 是否使用子进程或其他类似套接字的东西。由于克隆/分叉问题,我在使用 subprocess.check_output('ssh blah@blah.com "cat /data/file*") 时遇到内存问题,我想知道 paramiko 是否会遇到同样的问题? @Paul:paramiko 不会有同样的问题,因为它不使用子进程。【参考方案5】:

试试Python scp module for Paramiko。它非常易于使用。请参阅以下示例:

import paramiko
from scp import SCPClient

def createSSHClient(server, port, user, password):
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(server, port, user, password)
    return client

ssh = createSSHClient(server, port, user, password)
scp = SCPClient(ssh.get_transport())

然后拨打scp.get()scp.put()进行SCP操作。

(SCPClient code)

【讨论】:

除了该模块实际上并没有使用 paramiko - 有很多代码最终为 scp 最终实际调用了仅在 *nix 上工作的 scp 命令行。跨度> 同意,您在源代码中看到的是对scp -tscp -f 的远程调用('to' 和'from' 模式,存在用于此服务器端目的) .这本质上就是 scp 的工作方式——它依赖于服务器上存在的另一个 scp 副本。这篇文章解释的很好:blogs.oracle.com/janp/entry/how_the_scp_protocol_works 这个解决方案对我有用,但有两个注意事项:1. 这些是我使用的导入语句:import paramikofrom scp import SCPClient 2. 这是 scp.get() 命令的示例:@987654333 @ 这不仅效果很好,而且还可以利用 SSH 密钥(如果存在)。 我收到错误 scp.SCPException: scp Protocol not available 。我正在尝试将文件从 Windows 复制到 Mac。相同的命令在终端上运行良好。【参考方案6】:

看看fabric.transfer。

from fabric import Connection

with Connection(host="hostname", 
                user="admin", 
                connect_kwargs="key_filename": "/home/myuser/.ssh/private.key"
               ) as c:
    c.get('/foo/bar/file.txt', '/tmp/')

【讨论】:

你能说得更具体点吗? Fabric 目前不支持 scp。 (参考:github.com/fabric/fabric/issues/1948)【参考方案7】:

我之前整理了一个依赖于 paramiko 的 python SCP 复制脚本。它包括处理与私钥或 SSH 密钥代理的连接的代码,并回退到密码身份验证。

http://code.activestate.com/recipes/576810-copy-files-over-ssh-using-paramiko/

【讨论】:

感谢您的链接和花时间发布使用 paramiko 的好例子。【参考方案8】:

如果您在 *nix 上,您可以使用 sshpass

sshpass -p password scp -o User=username -o StrictHostKeyChecking=no src dst:/path

【讨论】:

【参考方案9】:

自从提出这个问题以来已经有一段时间了,与此同时,另一个可以处理这个问题的库已经出现: 您可以使用Plumbum 库中包含的copy 函数:

import plumbum
r = plumbum.machines.SshMachine("example.net")
   # this will use your ssh config as `ssh` from shell
   # depending on your config, you might also need additional
   # params, eg: `user="username", keyfile=".ssh/some_key"`
fro = plumbum.local.path("some_file")
to = r.path("/path/to/destination/")
plumbum.path.utils.copy(fro, to)

【讨论】:

如何使用 Plumbum 输入私钥的密码? p @ekta:将在命令行上提示您输入它。如果您想从自己的代码中提供它,我认为铅的 API 不支持这一点。但是plumbum 的SshMachine 确实可以访问ssh-agent,所以如果你只是想避免每次都输入它,这是一种方法。您也可以在 plumbum 的 github 页面上提交功能请求。【参考方案10】:

找不到直接的答案,而且这个“scp.Client”模块不存在。 相反,this 适合我:

from paramiko import SSHClient
from scp import SCPClient

ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect('example.com')

with SCPClient(ssh.get_transport()) as scp:
   scp.put('test.txt', 'test2.txt')
   scp.get('test2.txt')

【讨论】:

【参考方案11】:

您可以使用包子进程和命令调用从 shell 使用 scp 命令。

from subprocess import call

cmd = "scp user1@host1:files user2@host2:files"
call(cmd.split(" "))

【讨论】:

这与提问者提到的基本情况有何本质不同?是的,subprocess 比 os.system 好,但是在这两种情况下,它都不能在类 linux 系统之外工作,有密码提示等问题。【参考方案12】:

到目前为止,最好的解决方案可能是AsyncSSH

https://asyncssh.readthedocs.io/en/latest/#scp-client

async with asyncssh.connect('host.tld') as conn:
    await asyncssh.scp((conn, 'example.txt'), '.', recurse=True)

【讨论】:

嗨。你声称 AsyncSSH 是最好的,但你能发表一两个声明来支持这个声明吗?也许将它与 scp() 区分开来,或者它对您的用例有多重要。 (也就是说,它的代码要少得多——至少在你的例子中) @Crossfit_and_Beer 你好。所以我说“可能是最好的”,我会把判断交给任何人 :) 我现在没有太多时间将 AsyncSSH 与其他库进行比较。但很快:它使用简单,它是异步的,它是维护的,而且维护者非常好和乐于助人,它非常完整并且有很好的文档记录。 我采用了这个解决方案,它运行良好,同时传输超过 100 个。【参考方案13】:
import paramiko

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

client.connect('<IP Address>', username='<User Name>',password='' ,key_filename='<.PEM File path')

#Setup sftp connection and transmit this script 
print ("copying")

sftp = client.open_sftp() 
sftp.put(<Source>, <Destination>)


sftp.close()

【讨论】:

如果您在答案中添加一些评论来解释为什么您的解决方案是一个好的解决方案并帮助读者将其与其他可用的解决方案进行比较,这将有所帮助。仅仅发布代码并不总能帮助学习者知道如何识别更好的解决方案。 这是 SFTP,不是 SCP。

以上是关于如何在 Python 中进行 scp?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SCP 或 SSH 将文件复制到 Python 中的远程服务器?

python小脚本从数据库获取文件路径通过scp下载本地

如何在 Cygwin 上下载 SCP 和 ssh?

Windows XP下如何使用SCP命令将文件传到局域网中的Linux机器

如何解决ssh,scp程序报错的问题

如何在一行中使用用户名和密码执行 scp 命令[关闭]