如何在python scp?

Mic*_*ach 147 python ssh scp paramiko

在Python中scp文件的最pythonic方法是什么?我所知道的唯一途径是

os.system('scp "%s" "%s:%s"' % (localfile, remotehost, remotefile) )
Run Code Online (Sandbox Code Playgroud)

这是一个hack,并且在类似Linux的系统之外不起作用,并且需要Pexpect模块的帮助以避免密码提示,除非您已经将无密码SSH设置到远程主机.

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

我知道paramiko,一个支持ssh和sftp的Python模块; 但它不支持scp.

背景:我正在连接到不支持sftp但支持ssh/scp的路由器,所以sftp不是一个选项.

编辑:这是如何使用SCP或SSH将文件复制到Python中的远程服务器?. 但是,这个问题没有给出一个scp特定的答案来处理python中的键.我希望有一种运行代码的方式

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')
Run Code Online (Sandbox Code Playgroud)

小智 93

试试模块paramiko_scp.它非常易于使用.请参阅以下示例:

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())
Run Code Online (Sandbox Code Playgroud)

然后调用scp.get()或scp.put()来执行scp操作.

(SCPClient代码)

  • 同意,你在源代码中看到的是远程调用`scp -t`或`scp -f`('to'和'from'模式,这是为了服务器端目的而存在的).这实质上就是scp的工作原理 - 它依赖于服务器上现有的另一个scp副本.本文非常好地解释了它:https://blogs.oracle.com/janp/entry/how_the_scp_protocol_works (8认同)
  • 这个解决方案对我有两点需要注意:1.这些是我使用的import语句:`import paramiko``来自scp import SCPClient` 2.这是scp.get()命令的一个例子:`scp.get(r '/nfs_home/appers/xxxx/test2.txt',r'C:\ Users\xxxx\Desktop\MR_Test')` (7认同)
  • 除了该模块实际上并没有使用paramiko之外-许多代码最终使scp最终实际上调用了仅在* nix上可用的scp命令行。 (3认同)
  • @Nick Bastin,在linux和windows上都很棒 (2认同)

Pat*_*otz 14

您可能对尝试Pexpect(源代码)感兴趣.这将允许您处理密码的交互式提示.

以下是主网站上的示例用法(对于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')
Run Code Online (Sandbox Code Playgroud)


Jim*_*imB 10

你也可以查看paramiko.目前还没有scp模块,但它完全支持sftp.

[编辑]抱歉,错过了你提到paramiko的路线.以下模块只是paramiko的scp协议的一个实现.如果你不想使用paramiko或conch(我知道python的唯一ssh实现),你可以重做这个以使用管道运行常规ssh会话.

用于paramiko的scp.py

  • 这将使用运行sshd的任何机器传输文件,该机器在PATH中有scp(scp不是ssh规范的一部分,但它相当普遍).这会在服务器上调用"scp -t",并使用scp协议传输文件,这与sftp无关. (2认同)

Bla*_*ohr 6

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

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

(并且您可以使用油灰剂进行密钥管理)


对不起它只是一个黑客(但你可以把它包装在一个python类)


Mav*_*les 6

找不到直接的答案,这个"scp.Client"模块不存在.相反,适合我:

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')
Run Code Online (Sandbox Code Playgroud)


Loï*_*oïc 6

截至今天,最好的解决方案可能是 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)
Run Code Online (Sandbox Code Playgroud)

  • 你好。您声称 AsyncSSH 是最好的,但您能否发表一两个声明来支持这一声明?也许将它与 scp() 区分开来,或者它对您的用例有何影响。(这就是说,代码少得多 - 至少在你的例子中) (3认同)
  • @Crossfit_and_Beer 你好。所以我说“可能是最好的”,我会让任何人做出判断:)我现在没有太多时间将 AsyncSSH 与其他库进行比较。但很快:它使用简单,它是异步的,它是可维护的,并且维护者非常友善和乐于助人,它非常完整并且有很好的文档记录。 (3认同)
  • 我采用了这个解决方案,它表现良好,可同时进行 100 多个传输。 (2认同)

shr*_*xor 6

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()
Run Code Online (Sandbox Code Playgroud)

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

use*_*854 5

看一下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/')
Run Code Online (Sandbox Code Playgroud)

  • 你可以再详细一点吗? (2认同)

pmo*_*mos 5

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

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)
Run Code Online (Sandbox Code Playgroud)


小智 5

您可以使用包子进程和命令调用来从外壳程序使用scp命令。

from subprocess import call

cmd = "scp user1@host1:files user2@host2:files"
call(cmd.split(" "))
Run Code Online (Sandbox Code Playgroud)

  • 这与提问者提到的基本案例有何本质区别?是的,子进程比os.system更好,但是在两种情况下,它都无法在类似linux的系统之外运行,并且存在密码提示问题等。 (2认同)