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

时间:2022-06-05 02:48:32

I have a text file on my local machine that is generated by a daily Python script run in cron.

我在本地机器上有一个文本文件,它是由在cron中运行的日常Python脚本生成的。

I would like to add a bit of code to have that file sent securely to my server over SSH.

我想添加一些代码,以便通过SSH将该文件安全地发送到我的服务器。

11 个解决方案

#1


38  

If you want the simple approach, this should work.

如果您想要简单的方法,这应该是可行的。

You'll want to ".close()" the file first so you know it's flushed to disk from Python.

您将首先“.close()”文件,以便您知道它已从Python刷新到磁盘。

import os
os.system("scp FILE USER@SERVER:PATH")
#e.g. os.system("scp foo.bar joe@srvr.net:/path/to/foo.bar")

You need to generate (on the source machine) and install (on the destination machine) an ssh key beforehand so that the scp automatically gets authenticated with your public ssh key (in other words, so your script doesn't ask for a password).

您需要生成(在源机器上)并预先安装(在目标机器上)一个ssh密钥,以便scp自动通过您的公共ssh密钥进行身份验证(换句话说,您的脚本不会要求输入密码)。

ssh-keygen example

ssh - keygen例子

#2


118  

To do this in Python (i.e. not wrapping scp through subprocess.Popen or similar) with the Paramiko library, you would do something like this:

在Python中实现这一点(即不通过子进程包装scp)。在Paramiko图书馆,你可以这样做:

import os
import paramiko

ssh = paramiko.SSHClient() 
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username=username, password=password)
sftp = ssh.open_sftp()
sftp.put(localpath, remotepath)
sftp.close()
ssh.close()

(You would probably want to deal with unknown hosts, errors, creating any directories necessary, and so on).

(您可能希望处理未知的主机、错误、创建任何必要的目录等等)。

#3


28  

You'd probably use the subprocess module. Something like this:

您可能会使用子流程模块。是这样的:

import subprocess
p = subprocess.Popen(["scp", myfile, destination])
sts = os.waitpid(p.pid, 0)

Where destination is probably of the form user@remotehost:remotepath. Thanks to @Charles Duffy for pointing out the weakness in my original answer, which used a single string argument to specify the scp operation shell=True - that wouldn't handle whitespace in paths.

其中的目的地可能是表单user@remotehost:remotepath。感谢@Charles Duffy指出了我最初答案中的不足之处,它使用一个字符串参数指定scp操作shell=True——它不能在路径中处理空格。

The module documentation has examples of error checking that you may want to perform in conjunction with this operation.

模块文档中有一些错误检查的例子,您可能希望与此操作一起执行。

Ensure that you've set up proper credentials so that you can perform an unattended, passwordless scp between the machines. There is a * question for this already.

确保您已经设置了正确的凭证,这样您就可以在机器之间执行一个无人值守的、无密码的scp。这里有一个*的问题。

#4


10  

There are a couple of different ways to approach the problem:

有几种不同的方法来解决这个问题:

  1. Wrap command-line programs
  2. 用命令行程序
  3. use a Python library that provides SSH capabilities (eg - Paramiko or Twisted Conch)
  4. 使用提供SSH功能的Python库(如Paramiko或Twisted Conch)

Each approach has its own quirks. You will need to setup SSH keys to enable password-less logins if you are wrapping system commands like "ssh", "scp" or "rsync." You can embed a password in a script using Paramiko or some other library, but you might find the lack of documentation frustrating, especially if you are not familiar with the basics of the SSH connection (eg - key exchanges, agents, etc). It probably goes without saying that SSH keys are almost always a better idea than passwords for this sort of stuff.

每种方法都有自己的怪癖。如果您正在包装系统命令,如“SSH”、“scp”或“rsync”,则需要设置SSH密钥以启用无密码登录。您可以使用Paramiko或其他库在脚本中嵌入密码,但是您可能会发现文档的缺乏令人沮丧,特别是如果您不熟悉SSH连接的基础知识(例如,密钥交换、代理等)。毫无疑问,对于这类东西,SSH密钥几乎总是比密码好。

NOTE: its hard to beat rsync if you plan on transferring files via SSH, especially if the alternative is plain old scp.

注意:如果您计划通过SSH传输文件,那么很难打败rsync,尤其是如果替代方案是普通的旧scp。

I've used Paramiko with an eye towards replacing system calls but found myself drawn back to the wrapped commands due to their ease of use and immediate familiarity. You might be different. I gave Conch the once-over some time ago but it didn't appeal to me.

我使用Paramiko来代替系统调用,但由于使用方便和直接熟悉,我发现自己又回到了包装的命令中。你可能是不同的。一段时间以前,我曾给过海螺一次机会,但它并不吸引我。

If opting for the system-call path, Python offers an array of options such as os.system or the commands/subprocess modules. I'd go with the subprocess module if using version 2.4+.

如果选择系统调用路径,Python提供了一系列选项,如os。系统或命令/子进程模块。如果使用版本2.4+,我将使用子流程模块。

#5


4  

Reached the same problem, but instead of "hacking" or emulating command line:

达到了同样的问题,但不是“黑客”或模拟命令行:

Found this answer here.

发现了这个答案。

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

#6


2  

fabric could be used to upload files vis ssh:

fabric可以用于上传文件到vis ssh:

#!/usr/bin/env python
from fabric.api import execute, put
from fabric.network import disconnect_all

if __name__=="__main__":
    import sys
    # specify hostname to connect to and the remote/local paths
    srcdir, remote_dirname, hostname = sys.argv[1:]
    try:
        s = execute(put, srcdir, remote_dirname, host=hostname)
        print(repr(s))
    finally:
        disconnect_all()

#7


1  

I used sshfs to mount the remote directory via ssh, and shutil to copy the files:

我使用sshfs通过ssh挂载远程目录,shutil复制文件:

$ mkdir ~/sshmount
$ sshfs user@remotehost:/path/to/remote/dst ~/sshmount

Then in python:

然后在python中:

import shutil
shutil.copy('a.txt', '~/sshmount')

This method has the advantage that you can stream data over if you are generating data rather than caching locally and sending a single large file.

这种方法的优点是,如果您正在生成数据,而不是在本地缓存并发送单个大文件,则可以将数据流遍。

#8


0  

Calling scp command via subprocess doesn't allow to receive the progress report inside the script. pexpect could be used to extract that info:

通过子进程调用scp命令不允许在脚本中接收进度报告。pexpect可以用来提取信息:

import pipes
import re
import pexpect # $ pip install pexpect

def progress(locals):
    # extract percents
    print(int(re.search(br'(\d+)%$', locals['child'].after).group(1)))

command = "scp %s %s" % tuple(map(pipes.quote, [srcfile, destination]))
pexpect.run(command, events={r'\d+%': progress})

See python copy file in local network (linux -> linux)

参见本地网络中的python拷贝文件(linux -> linux)

#9


0  

from paramiko import SSHClient
from scp import SCPClient
import os

ssh = SSHClient() 
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username='username', password='password')
with SCPClient(ssh.get_transport()) as scp:
        scp.put('test.txt', 'test2.txt')

#10


0  

a very simple approach is the following:

一个非常简单的办法是:

import os
sshpass -p "password" scp user@host:/path/to/file ./

no python library are required (only os) and it works

不需要任何python库(只需要操作系统),它可以工作

#11


-1  

Kind of hacky, but the following should work :)

有点陈腐,但以下几点应该行得通:

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)

#1


38  

If you want the simple approach, this should work.

如果您想要简单的方法,这应该是可行的。

You'll want to ".close()" the file first so you know it's flushed to disk from Python.

您将首先“.close()”文件,以便您知道它已从Python刷新到磁盘。

import os
os.system("scp FILE USER@SERVER:PATH")
#e.g. os.system("scp foo.bar joe@srvr.net:/path/to/foo.bar")

You need to generate (on the source machine) and install (on the destination machine) an ssh key beforehand so that the scp automatically gets authenticated with your public ssh key (in other words, so your script doesn't ask for a password).

您需要生成(在源机器上)并预先安装(在目标机器上)一个ssh密钥,以便scp自动通过您的公共ssh密钥进行身份验证(换句话说,您的脚本不会要求输入密码)。

ssh-keygen example

ssh - keygen例子

#2


118  

To do this in Python (i.e. not wrapping scp through subprocess.Popen or similar) with the Paramiko library, you would do something like this:

在Python中实现这一点(即不通过子进程包装scp)。在Paramiko图书馆,你可以这样做:

import os
import paramiko

ssh = paramiko.SSHClient() 
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username=username, password=password)
sftp = ssh.open_sftp()
sftp.put(localpath, remotepath)
sftp.close()
ssh.close()

(You would probably want to deal with unknown hosts, errors, creating any directories necessary, and so on).

(您可能希望处理未知的主机、错误、创建任何必要的目录等等)。

#3


28  

You'd probably use the subprocess module. Something like this:

您可能会使用子流程模块。是这样的:

import subprocess
p = subprocess.Popen(["scp", myfile, destination])
sts = os.waitpid(p.pid, 0)

Where destination is probably of the form user@remotehost:remotepath. Thanks to @Charles Duffy for pointing out the weakness in my original answer, which used a single string argument to specify the scp operation shell=True - that wouldn't handle whitespace in paths.

其中的目的地可能是表单user@remotehost:remotepath。感谢@Charles Duffy指出了我最初答案中的不足之处,它使用一个字符串参数指定scp操作shell=True——它不能在路径中处理空格。

The module documentation has examples of error checking that you may want to perform in conjunction with this operation.

模块文档中有一些错误检查的例子,您可能希望与此操作一起执行。

Ensure that you've set up proper credentials so that you can perform an unattended, passwordless scp between the machines. There is a * question for this already.

确保您已经设置了正确的凭证,这样您就可以在机器之间执行一个无人值守的、无密码的scp。这里有一个*的问题。

#4


10  

There are a couple of different ways to approach the problem:

有几种不同的方法来解决这个问题:

  1. Wrap command-line programs
  2. 用命令行程序
  3. use a Python library that provides SSH capabilities (eg - Paramiko or Twisted Conch)
  4. 使用提供SSH功能的Python库(如Paramiko或Twisted Conch)

Each approach has its own quirks. You will need to setup SSH keys to enable password-less logins if you are wrapping system commands like "ssh", "scp" or "rsync." You can embed a password in a script using Paramiko or some other library, but you might find the lack of documentation frustrating, especially if you are not familiar with the basics of the SSH connection (eg - key exchanges, agents, etc). It probably goes without saying that SSH keys are almost always a better idea than passwords for this sort of stuff.

每种方法都有自己的怪癖。如果您正在包装系统命令,如“SSH”、“scp”或“rsync”,则需要设置SSH密钥以启用无密码登录。您可以使用Paramiko或其他库在脚本中嵌入密码,但是您可能会发现文档的缺乏令人沮丧,特别是如果您不熟悉SSH连接的基础知识(例如,密钥交换、代理等)。毫无疑问,对于这类东西,SSH密钥几乎总是比密码好。

NOTE: its hard to beat rsync if you plan on transferring files via SSH, especially if the alternative is plain old scp.

注意:如果您计划通过SSH传输文件,那么很难打败rsync,尤其是如果替代方案是普通的旧scp。

I've used Paramiko with an eye towards replacing system calls but found myself drawn back to the wrapped commands due to their ease of use and immediate familiarity. You might be different. I gave Conch the once-over some time ago but it didn't appeal to me.

我使用Paramiko来代替系统调用,但由于使用方便和直接熟悉,我发现自己又回到了包装的命令中。你可能是不同的。一段时间以前,我曾给过海螺一次机会,但它并不吸引我。

If opting for the system-call path, Python offers an array of options such as os.system or the commands/subprocess modules. I'd go with the subprocess module if using version 2.4+.

如果选择系统调用路径,Python提供了一系列选项,如os。系统或命令/子进程模块。如果使用版本2.4+,我将使用子流程模块。

#5


4  

Reached the same problem, but instead of "hacking" or emulating command line:

达到了同样的问题,但不是“黑客”或模拟命令行:

Found this answer here.

发现了这个答案。

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

#6


2  

fabric could be used to upload files vis ssh:

fabric可以用于上传文件到vis ssh:

#!/usr/bin/env python
from fabric.api import execute, put
from fabric.network import disconnect_all

if __name__=="__main__":
    import sys
    # specify hostname to connect to and the remote/local paths
    srcdir, remote_dirname, hostname = sys.argv[1:]
    try:
        s = execute(put, srcdir, remote_dirname, host=hostname)
        print(repr(s))
    finally:
        disconnect_all()

#7


1  

I used sshfs to mount the remote directory via ssh, and shutil to copy the files:

我使用sshfs通过ssh挂载远程目录,shutil复制文件:

$ mkdir ~/sshmount
$ sshfs user@remotehost:/path/to/remote/dst ~/sshmount

Then in python:

然后在python中:

import shutil
shutil.copy('a.txt', '~/sshmount')

This method has the advantage that you can stream data over if you are generating data rather than caching locally and sending a single large file.

这种方法的优点是,如果您正在生成数据,而不是在本地缓存并发送单个大文件,则可以将数据流遍。

#8


0  

Calling scp command via subprocess doesn't allow to receive the progress report inside the script. pexpect could be used to extract that info:

通过子进程调用scp命令不允许在脚本中接收进度报告。pexpect可以用来提取信息:

import pipes
import re
import pexpect # $ pip install pexpect

def progress(locals):
    # extract percents
    print(int(re.search(br'(\d+)%$', locals['child'].after).group(1)))

command = "scp %s %s" % tuple(map(pipes.quote, [srcfile, destination]))
pexpect.run(command, events={r'\d+%': progress})

See python copy file in local network (linux -> linux)

参见本地网络中的python拷贝文件(linux -> linux)

#9


0  

from paramiko import SSHClient
from scp import SCPClient
import os

ssh = SSHClient() 
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username='username', password='password')
with SCPClient(ssh.get_transport()) as scp:
        scp.put('test.txt', 'test2.txt')

#10


0  

a very simple approach is the following:

一个非常简单的办法是:

import os
sshpass -p "password" scp user@host:/path/to/file ./

no python library are required (only os) and it works

不需要任何python库(只需要操作系统),它可以工作

#11


-1  

Kind of hacky, but the following should work :)

有点陈腐,但以下几点应该行得通:

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)