tags:

views:

9876

answers:

5

What's the most pythonic way to scp a file in Python? The only route I'm aware of is

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

which is a hack, and which doesn't work outside linux-like systems, and which needs help from the Pexpect module to avoid password prompts unless you already have passwordless SSH set up to the remote host.

I'm aware of Twisted's conch, but I'd prefer to avoid implementing scp myself via low-level ssh modules.

I'm aware of paramiko, a Python module that supports ssh and sftp; but it doesn't support scp.

Background: I'm connecting to a router which doesn't support sftp but does support ssh/scp, so sftp isn't an option.

EDIT: This is a duplicate of http://stackoverflow.com/questions/68335/how-do-i-copy-a-file-to-a-remote-server-in-python-using-scp-or-ssh. However, that question doesn't give an scp-specific answer that deals with keys from within python. I'm hoping for a way to run code kind of like

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')
A: 

I don't think there's any one module that you can easily download to implement scp, however you might find this helpful: http://www.ibm.com/developerworks/linux/library/l-twist4.html

m0j0
+3  A: 

if you install putty on win32 you get an pscp (putty scp).

so you can use the os.system hack on win32 too.

(and you can use the putty-agent for key-managment)


sorry it is only a hack (but you can wrap it in a python class)

Blauohr
The only reason the 'nix one works is, you have SCP on the path; as Blauohr points out, that's not too hard to fix. +1
ojrac
+3  A: 

You might be interested in trying Pexpect (SourceForge project). This would allow you to deal with interactive prompts for your password.

Here's a snip of example usage (for ftp) from the main website:

   # 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 ('[email protected]')
   child.expect ('ftp> ')
   child.sendline ('cd pub')
   child.expect('ftp> ')
   child.sendline ('get ls-lR.gz')
   child.expect('ftp> ')
   child.sendline ('bye')
Pat Notz
Thanks. Incorporated into my Question.
Michael Gundlach
+1  A: 

Hmmm, perhaps another option would be to use something like sshfs (there an sshfs for Mac too). Once your router is mounted you can just copy the files outright. I'm not sure if that works for your particular application but it's a nice solution to keep handy.

Pat Notz
+2  A: 

You could also check out paramiko. There's no scp module (yet), but it fully supports sftp.

[EDIT] Sorry, missed the line where you mentioned paramiko. The following module is simply an implementation of the scp protocol for paramiko. If you don't want to use paramiko or conch (the only ssh implementations I know of for python), you could rework this to run over a regular ssh session using pipes.

scp.py for paramiko

JimB
Are you saying that the attached solution will securely transfer files to any machine running sshd, even if it's not running sftpd? That's exactly what I'm looking for, but I can't tell from your comment whether this just wraps sftp in an scp-like facade.
Michael Gundlach
This will transfer files with any machine running sshd, which has scp in the PATH (scp isn't part of the ssh spec, but it's fairly ubiquitous). This invokes "scp -t" on the server, and uses the scp protocol to transfer files, which has nothing to do with sftp.
JimB
Please note that I used openssh's implementation of scp as the model, so this isn't guaranteed to work with other versions. Some versions of sshd may also use the scp2 protocol, which is basically the same as sftp.
JimB