2008-09-16 17 views
74

У меня есть текстовый файл на моей локальной машине, который генерируется ежедневным скриптом Python, запущенным в cron.Как скопировать файл на удаленный сервер в Python с помощью SCP или SSH?

Я хотел бы добавить немного кода, чтобы этот файл был надежно отправлен на мой сервер через SSH.

+1

нашли нечто подобное, может у взглянуть http://stackoverflow.com/questions/11009308/copying-logs-in-python-using-the-command-line-function – JJ84 2012-06-13 07:02:23

ответ

36

Если вы хотите простой подход, это должно сработать.

Вы сначала захотите «.close()», чтобы вы знали, что он сброшен на диск с Python.

import os 
os.system("scp FILE [email protected]:PATH") 
#e.g. os.system("scp foo.bar [email protected]:/path/to/foo.bar") 

Вам необходимо заранее произвести (на исходной машине) и установите (на целевом компьютере) ключа SSH, так что УПП автоматически получает проверку подлинности с помощью открытого ключа SSH (другими словами, так что ваш сценарий Безразлично не запрашивать пароль).

ssh-keygen example

+26

subprocess.Popen (["scp", filename, "% (user) s @% (server) s:% (remotepath) s"% vars]). wait() - гораздо лучший подход, чем os.system(), который не правильно обрабатывать имена файлов с пробелами. – 2008-10-15 12:06:40

+0

@Charles Что такое обозначение «%», которое вы используете здесь? Я хотел бы прочитать документацию по ее функциональности. – KomodoDave 2012-08-15 11:11:51

+1

Nevermind, нашел его. Найдите «коды формата python» или «операции форматирования строки python». Оператор «%» известен как «оператор форматирования строк» ​​или «оператор интерполяции строк». – KomodoDave 2012-08-15 11:18:50

-1

Вид Hacky, но должно работать :)

import os 
filePath = "/foo/bar/baz.py" 
serverPath = "/blah/boo/boom.py" 
os.system("scp "+filePath+" [email protected]:"+serverPath) 
28

Вы бы, вероятно, использовать subprocess module. Что-то вроде этого:

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

destination Где, вероятно, в форме [email protected]:remotepath. Благодаря @Charles Duffy за то, что он указал на слабость моего первоначального ответа, который использовал один строковый аргумент, чтобы указать операцию scp shell=True - это не будет обрабатывать пробелы в путях.

Документация Модуль имеет examples of error checking that you may want to perform in conjunction with this operation.

Убедитесь, что вы настроили соответствующие учетные данные, так что вы можете выполнить unattended, passwordless scp between the machines. Существует stackoverflow question for this already.

10

Есть несколько различных способов подойти к решению проблемы:

  1. Wrap программы командной строки
  2. использовать библиотеку Python, которая предоставляет возможности SSH (например - Paramiko или Twisted Conch)

Каждый подход имеет свои собственные причуды. Вам нужно будет настроить SSH-ключи, чтобы включить учетные записи без пароля, если вы обмениваете системные команды, такие как «ssh», «scp» или «rsync». Вы можете вставлять пароль в сценарий, используя Paramiko или какую-либо другую библиотеку, но вы можете обнаружить, что недостаток документации разочаровывает, особенно если вы не знакомы с основами SSH-соединения (например, обмен ключами, агенты и т. Д.). Вероятно, само собой разумеется, что ключи SSH почти всегда лучше, чем пароли для такого рода вещей.

ПРИМЕЧАНИЕ: его трудно бить rsync, если вы планируете передавать файлы через SSH, особенно если альтернатива - это простой старый scp.

Я использовал Парамико с целью замены системных вызовов, но обнаружил, что обращается к завернутым командам из-за их простоты использования и непосредственного знакомства. Вы можете быть разными. Некоторое время назад я дал Кончу, но это не понравилось мне.

Если вы выбираете путь системного вызова, Python предлагает массив таких параметров, как os.system или команды/подпроцессы. Я бы пошел с модулем подпроцесса при использовании версии 2.4+.

113

Чтобы сделать это в Python (т.е. не оборачивать УПП через subprocess.Popen или аналогичный) с 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() 

(Вы, вероятно, хотите иметь дело с неизвестными хозяевами , ошибки, создание любых необходимых каталогов и т. д.).

2

fabric может быть использован для загрузки файлов по отношению 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() 
0

Вызов 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}) 

См python copy file in local network (linux -> linux)

4

Достигнута такая же проблема, но вместо «взлома» или эмуляции командной строки:

этот ответ 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') 
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') 
0

очень простой подход заключается в следующем:

import os 
sshpass -p "password" scp [email protected]:/path/to/file ./ 

нет библиотеки Python не требуется (только ОС) и он работает

1

Я использовал sshfs смонтировать удаленный каталог с помощью ssh и shutil, чтобы скопировать файлы:

$ mkdir ~/sshmount 
$ sshfs [email protected]:/path/to/remote/dst ~/sshmount 

Тогда в питоне:

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

Этот метод имеет то преимущество, что вы можете передавать данные через если вы генерируете данные, а не кэшировать локально и посылая один большой файл.