Wie scp in Python?

158

Was ist die pythonischste Art, eine Datei in Python zu scpen? Der einzige Weg, den ich kenne, ist

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

Dies ist ein Hack, der außerhalb von Linux-ähnlichen Systemen nicht funktioniert und der Hilfe vom Pexpect-Modul benötigt, um Kennwortabfragen zu vermeiden, es sei denn, Sie haben bereits kennwortloses SSH auf dem Remote-Host eingerichtet.

Ich bin mir Twisted's bewusst conch, aber ich würde es vorziehen, die Implementierung von scp selbst über Low-Level-SSH-Module zu vermeiden.

Mir ist bekannt paramiko, ein Python-Modul, das SSH und SFTP unterstützt. SCP wird jedoch nicht unterstützt.

Hintergrund: Ich verbinde mich mit einem Router, der SFTP nicht unterstützt, aber SSH / SCP unterstützt, sodass SFTP keine Option ist.

BEARBEITEN : Dies ist ein Duplikat von Wie kopiere ich eine Datei mit SCP oder SSH auf einen Remote-Server in Python? . Diese Frage gibt jedoch keine scp-spezifische Antwort, die sich mit Schlüsseln aus Python befasst. Ich hoffe auf eine Möglichkeit, Code so ähnlich auszuführen

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')
Michael Gundlach
quelle

Antworten:

106

Probieren Sie das Python-scp-Modul für Paramiko aus . Es ist sehr einfach zu bedienen. Siehe folgendes Beispiel:

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

Rufen Sie dann an scp.get()oder scp.put()führen Sie SCP-Operationen aus.

( SCPClient-Code )

Tom Shen
quelle
3
Abgesehen davon, dass das Modul nicht wirklich paramiko verwendet - es ist eine Menge Code, der am Ende scptatsächlich die scpBefehlszeile aufruft , die nur unter * nix funktioniert.
Nick Bastin
8
Einverstanden, was Sie im Quellcode sehen, ist der Remote-Aufruf von scp -toder scp -f('zu' und 'von' Modi, die für diesen serverseitigen Zweck existieren). So funktioniert scp im Wesentlichen - es basiert auf einer anderen Kopie von scp, die auf dem Server vorhanden ist. Dieser Artikel erklärt es sehr gut: blogs.oracle.com/janp/entry/how_the_scp_protocol_works
laher
8
Diese Lösung funktionierte für mich mit zwei Einschränkungen: 1. Dies sind die Importanweisungen, die ich verwendet habe: import paramiko from scp import SCPClient2. Hier ist ein Beispiel für den Befehl scp.get ():scp.get(r'/nfs_home/appers/xxxx/test2.txt', r'C:\Users\xxxx\Desktop\MR_Test')
Chris Nielsen
Dies funktioniert nicht nur hervorragend, sondern nutzt auch SSH-Schlüssel, falls vorhanden.
Marcel Wilson
Beachten Sie, dass Sie diese Bibliothek auch über PyPI installieren können: pip install scpab Version 0.10.2.
Andrew B.
15

Möglicherweise möchten Sie Pexpect ( Quellcode ) ausprobieren . Auf diese Weise können Sie interaktive Eingabeaufforderungen für Ihr Kennwort bearbeiten.

Hier ist ein Auszug aus der Beispielverwendung (für FTP) von der Hauptwebsite:

# 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
quelle
11

Sie können auch paramiko ausprobieren . Es gibt (noch) kein scp-Modul, aber es unterstützt sftp vollständig.

[BEARBEITEN] Entschuldigung, ich habe die Zeile verpasst, in der Sie paramiko erwähnt haben. Das folgende Modul ist einfach eine Implementierung des scp-Protokolls für paramiko. Wenn Sie kein Paramiko oder Conch verwenden möchten (die einzigen mir bekannten SSH-Implementierungen für Python), können Sie dies überarbeiten, um eine reguläre SSH-Sitzung mit Pipes auszuführen.

scp.py für paramiko

JimB
quelle
Wollen Sie damit sagen, dass die angehängte Lösung Dateien sicher auf jeden Computer überträgt, auf dem sshd ausgeführt wird, auch wenn sftpd nicht ausgeführt wird? Das ist genau das, wonach ich suche, aber ich kann anhand Ihres Kommentars nicht sagen, ob dies nur SFTP in eine scp-ähnliche Fassade einwickelt.
Michael Gundlach
2
Dadurch werden Dateien mit jedem Computer übertragen, auf dem sshd ausgeführt wird und dessen Pfad scp enthält (scp ist nicht Teil der ssh-Spezifikation, aber ziemlich allgegenwärtig). Dies ruft "scp -t" auf dem Server auf und verwendet das scp-Protokoll zum Übertragen von Dateien, was nichts mit sftp zu tun hat.
JimB
1
Bitte beachten Sie, dass ich die Implementierung von scp von openssh als Modell verwendet habe, sodass dies nicht garantiert mit anderen Versionen funktioniert. Einige Versionen von sshd verwenden möglicherweise auch das scp2-Protokoll, das im Grunde dasselbe ist wie sftp.
JimB
Könnten Sie bitte diese Frage sehen: stackoverflow.com/questions/20111242/… Ich frage mich, ob paramiko einen Unterprozess verwendet oder etwas anderes wie Sockets. Ich habe Speicherprobleme bei der Verwendung von subprocess.check_output ('ssh [email protected] "cat / data / file *") aufgrund von Klon- / Gabelproblemen und frage mich, ob paramiko dieselben Probleme haben wird oder nicht.
Paul
1
@Paul: paramiko hat nicht die gleichen Probleme, da es keinen Unterprozess verwendet.
JimB
9

Es konnte keine eindeutige Antwort gefunden werden, und dieses "scp.Client" -Modul ist nicht vorhanden. Stattdessen diese passt zu mir:

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')
Maviles
quelle
6

Wenn Sie Putty auf Win32 installieren, erhalten Sie ein PSCP (Putty SCP).

Sie können also den os.system-Hack auch für win32 verwenden.

(und Sie können den Putty-Agent für die Schlüsselverwaltung verwenden)


Entschuldigung, es ist nur ein Hack (aber Sie können es in eine Python-Klasse einwickeln)

Blauohr
quelle
Der einzige Grund, warum das Nix funktioniert, ist, dass Sie SCP auf dem Pfad haben. Wie Blauohr betont, ist das nicht allzu schwer zu beheben. +1
ojrac
6

Sie können den Paketunterprozess und den Befehlsaufruf verwenden, um den Befehl scp aus der Shell zu verwenden.

from subprocess import call

cmd = "scp user1@host1:files user2@host2:files"
call(cmd.split(" "))
user7529863
quelle
2
Wie unterscheidet sich dies wesentlich von dem vom Fragesteller erwähnten Basisfall? Ja, Subprozess ist besser als os.system, aber in beiden Fällen funktioniert es nicht außerhalb von Linux-ähnlichen Systemen, hat Probleme mit Passwortabfragen usw.
Foon
5

Ab heute ist wahrscheinlich die beste Lösung 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)
Loïc
quelle
1
Hallo. Sie behaupten, dass AsyncSSH das Beste ist, aber könnten Sie eine oder zwei Aussagen machen, um diese Behauptung zu unterstützen? Vielleicht unterscheiden Sie es von scp () oder wie es für Ihren Anwendungsfall wichtig war. (Das heißt, es ist viel weniger Code - zumindest in Ihrem Beispiel)
Scott Prive
2
@ Crossfit_and_Beer hallo. Also sagte ich "wahrscheinlich das Beste", ich werde das Urteil jedem überlassen :) Ich habe momentan nicht viel Zeit, um AsyncSSH mit anderen Bibliotheken zu vergleichen. Aber sehr schnell: Es ist einfach zu bedienen, asynchron, wird gewartet und der Maintener ist sehr nett und hilfreich, er ist ziemlich vollständig und sehr gut dokumentiert.
Loïc
5

Schauen Sie sich Fabric.Transfer an .

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/')
user443854
quelle
2
Könnten Sie genauer sein?
Nick T
4

Es ist schon eine ganze Weile , da diese Frage gestellt wurde, und in der Zwischenzeit eine andere Bibliothek , die diese beschnitten hat handhaben kann: Sie können die verwenden können Kopie in der mitgelieferten Funktion Plumbum Bibliothek:

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)
pmos
quelle
Wie kann ich mit Plumbum die Passphrase für den privaten Schlüssel eingeben? p
ekta
@ekta: Sie werden in der Befehlszeile dazu aufgefordert. Wenn Sie es aus Ihrem eigenen Code bereitstellen möchten, unterstützt die API von plumbum dies meiner Meinung nach nicht. Aber Plumbum's SshMachinehat Zugriff darauf ssh-agent. Wenn Sie also vermeiden möchten, es jedes Mal einzugeben, ist dies eine Möglichkeit, dies zu tun. Sie können auch eine Funktionsanforderung auf der Github-Seite von plumbum einreichen.
pmos
2

Wenn Sie auf * nix sind, können Sie sshpass verwenden

sshpass -p password scp -o User=username -o StrictHostKeyChecking=no src dst:/path
user178047
quelle
2
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()
Shrikkanth Roxor
quelle
Es wäre hilfreich, wenn Sie Ihrer Antwort einen Kommentar hinzufügen würden, der erklärt, warum Ihre Lösung gut ist, und den Lesern helfen würden, sie mit den anderen verfügbaren Lösungen zu vergleichen. Nur der Posting-Code hilft dem Lernenden nicht immer, bessere Lösungen zu erkennen.
Brian Tompsett - 莱恩 莱恩
Dies ist SFTP, nicht SCP.
Martin Prikryl
1

Hmmm, vielleicht wäre eine andere Option, so etwas wie sshfs zu verwenden (es gibt auch ein sshfs für Mac). Sobald Ihr Router bereitgestellt ist, können Sie die Dateien direkt kopieren. Ich bin mir nicht sicher, ob das für Ihre spezielle Anwendung funktioniert, aber es ist eine gute Lösung, um es griffbereit zu halten.

Pat Notz
quelle
1

Ich habe vor einiger Zeit ein Python-SCP-Kopierskript zusammengestellt, das von paramiko abhängt. Es enthält Code zur Verarbeitung von Verbindungen mit einem privaten Schlüssel oder einem SSH-Schlüsselagenten mit einem Fallback auf die Kennwortauthentifizierung.

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

ccpizza
quelle
Vielen Dank für den Link und dafür, dass Sie sich die Zeit genommen haben, ein gutes Beispiel für die Verwendung von paramiko zu veröffentlichen.
Peter M. - steht für Monica