Bagaimana cara scp menggunakan Python?


158

Apa cara paling pythonic untuk scp file dengan Python? Satu-satunya rute yang saya ketahui adalah

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

yang merupakan peretasan, dan yang tidak berfungsi di luar sistem seperti Linux, dan yang membutuhkan bantuan dari modul Pexpect untuk menghindari permintaan kata sandi kecuali Anda sudah menyiapkan SSH tanpa kata sandi yang diatur ke host jarak jauh.

Saya mengetahui Twisted's conch, tetapi saya lebih suka menghindari mengimplementasikan scp sendiri melalui modul ssh tingkat rendah.

Saya tahu paramiko, modul Python yang mendukung SSH dan SFTP; tetapi tidak mendukung SCP.

Latar Belakang: Saya tersambung ke router yang tidak mendukung SFTP tetapi mendukung SSH / SCP, jadi SFTP bukan pilihan.

EDIT : Ini adalah duplikat dari Bagaimana cara menyalin file ke server jauh di Python menggunakan SCP atau SSH? . Namun , pertanyaan itu tidak memberikan jawaban khusus-scp yang berhubungan dengan kunci dari dalam Python. Saya berharap cara menjalankan kode sejenisnya

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

Jawaban:


106

Coba modul Python scp untuk Paramiko . Ini sangat mudah digunakan. Lihat contoh berikut:

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

Kemudian panggil scp.get()atau scp.put()untuk melakukan operasi SCP.

( Kode SCPClient )


3
Kecuali modul itu tidak benar-benar menggunakan paramiko - banyak kode yang pada akhirnya scpberakhir benar-benar memanggil scpbaris perintah yang hanya berfungsi pada * nix.
Nick Bastin

8
Setuju, apa yang Anda lihat dalam kode sumber adalah panggilan jarak jauh ke scp -tatau scp -f(mode 'ke' dan 'dari', yang ada untuk tujuan sisi server ini). Ini pada dasarnya bagaimana scp bekerja - ia bergantung pada salinan scp lain yang ada di server. Artikel ini menjelaskannya dengan sangat baik: blogs.oracle.com/janp/entry/how_the_scp_protocol_works
laher

8
Solusi ini bekerja untuk saya dengan dua peringatan: 1. ini adalah pernyataan impor yang saya gunakan: import paramiko from scp import SCPClient2. Berikut adalah contoh dari perintah scp.get ():scp.get(r'/nfs_home/appers/xxxx/test2.txt', r'C:\Users\xxxx\Desktop\MR_Test')
Chris Nielsen

Ini tidak hanya berfungsi dengan baik, tetapi juga memanfaatkan kunci SSH jika ada.
Marcel Wilson

Perhatikan bahwa Anda dapat menginstal lib ini dari PyPI juga pip install scp:, di versi 0.10.2 saat tulisan ini dibuat.
Andrew B.

15

Anda mungkin tertarik untuk mencoba Pexpect ( kode sumber ). Ini akan memungkinkan Anda untuk berurusan dengan permintaan interaktif untuk kata sandi Anda.

Berikut cuplikan contoh penggunaan (untuk ftp) dari situs web utama:

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

11

Anda juga bisa memeriksa paramiko . Tidak ada modul scp (belum), tetapi sepenuhnya mendukung sftp.

[EDIT] Maaf, melewatkan baris di mana Anda menyebutkan paramiko. Modul berikut hanyalah implementasi protokol scp untuk paramiko. Jika Anda tidak ingin menggunakan paramiko atau keong (satu-satunya implementasi ssh yang saya tahu untuk python), Anda bisa mengerjakan ulang ini untuk menjalankan sesi ssh biasa menggunakan pipa.

scp.py untuk paramiko


Apakah Anda mengatakan bahwa solusi terlampir akan mentransfer file dengan aman ke mesin apa pun yang menjalankan sshd, bahkan jika itu tidak menjalankan sftpd? Itulah tepatnya yang saya cari, tetapi saya tidak bisa mengatakan dari komentar Anda apakah ini hanya membungkus sftp dalam fasad seperti scp.
Michael Gundlach

2
Ini akan mentransfer file dengan mesin apa saja yang menjalankan sshd, yang memiliki scp di PATH (scp bukan bagian dari spesifikasi ssh, tapi ini cukup di mana-mana). Ini memanggil "scp -t" di server, dan menggunakan protokol scp untuk mentransfer file, yang tidak ada hubungannya dengan sftp.
JimB

1
Harap dicatat bahwa saya menggunakan implementasi scp sebagai model openssh, jadi ini tidak dijamin untuk bekerja dengan versi lain. Beberapa versi sshd juga dapat menggunakan protokol scp2, yang pada dasarnya sama dengan sftp.
JimB

Bisakah Anda melihat pertanyaan ini: stackoverflow.com/questions/20111242/... Saya ingin tahu apakah paramiko menggunakan subproses atau membuat yang lain seperti soket. Saya mengalami masalah memori menggunakan subprocess.check_output ('ssh blah@blah.com "cat / data / file *") karena masalah kloning / garpu dan saya bertanya-tanya apakah paramiko akan memiliki masalah yang sama atau tidak?
Paul

1
@ Paul: paramiko tidak akan memiliki masalah yang sama, karena tidak menggunakan subproses.
JimB

9

Tidak dapat menemukan jawaban langsung, dan modul "scp.Client" ini tidak ada. Sebaliknya, ini cocok untuk saya:

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

jika Anda memasang dempul pada win32 Anda mendapatkan pscp (dempul scp).

sehingga Anda dapat menggunakan sistem hack os.s pada win32 juga.

(dan Anda dapat menggunakan agen dempul untuk manajemen kunci)


maaf itu hanya hack (tetapi Anda bisa membungkusnya dengan kelas python)


Satu-satunya alasan 'nix one berfungsi adalah, Anda memiliki SCP di jalurnya; seperti yang ditunjukkan Blauohr, itu tidak terlalu sulit untuk diperbaiki. +1
ojrac

6

Anda dapat menggunakan subproses paket dan panggilan perintah untuk menggunakan perintah scp dari shell.

from subprocess import call

cmd = "scp user1@host1:files user2@host2:files"
call(cmd.split(" "))

2
Bagaimana ini secara substansial berbeda dari kasus dasar yang disebutkan oleh penanya? Ya, subproses lebih baik daripada sistem os.s, tetapi dalam kedua kasus, itu tidak bekerja di luar sistem seperti linux, memiliki masalah dengan kata sandi, dll.
Foon

5

Sampai hari ini, solusi terbaik mungkin 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)

1
Hai. Anda membuat klaim tentang AsyncSSH sebagai yang terbaik, tetapi bisakah Anda membuat pernyataan atau 2 untuk mendukung klaim ini? Mungkin membedakannya dari scp (), atau bagaimana masalahnya bagi kasus penggunaan Anda. (Dikatakan, ini jauh lebih sedikit kode - dalam contoh Anda setidaknya)
Scott Prive

2
@Crossfit_and_Beer halo. Jadi saya berkata "mungkin yang terbaik", saya akan memberikan penilaian kepada siapa pun :) Saya tidak punya banyak waktu sekarang untuk membandingkan AsyncSSH dengan perpustakaan lain. Tetapi sangat cepat: mudah digunakan, asinkron, dirawat dan pemelihara sangat baik dan bermanfaat, cukup lengkap dan didokumentasikan dengan sangat baik.
Loïc

5

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

2
Bisakah kamu lebih spesifik?
Nick T

4

Sudah cukup lama sejak pertanyaan ini diajukan, dan sementara itu, pustaka lain yang dapat menangani ini telah terpotong: Anda dapat menggunakan fungsi salin yang termasuk dalam pustaka 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)

Bagaimana saya bisa memasukkan frasa sandi untuk kunci pribadi dengan Timah? p
ekta

@ekta: Anda akan diminta untuk melakukannya di baris perintah. Jika Anda ingin menyediakannya dari kode Anda sendiri, saya kira API timbal tidak mendukung hal ini. Tetapi timbal SshMachinememang memiliki akses ssh-agent, jadi jika Anda hanya ingin menghindari mengetik setiap waktu, itu salah satu cara untuk melakukannya. Anda juga dapat mengajukan permintaan fitur pada halaman github timbal.
pmos

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

Akan membantu jika Anda menambahkan beberapa komentar pada jawaban Anda yang menjelaskan mengapa solusi Anda bagus dan membantu pembaca membandingkannya dengan solusi lain yang tersedia. Hanya memposting kode tidak selalu membantu pelajar mengetahui bagaimana mengenali solusi yang lebih baik.
Brian Tompsett - 汤 莱恩

Ini SFTP, bukan SCP.
Martin Prikryl

2

Jika Anda menggunakan * nix, Anda dapat menggunakan sshpass

sshpass -p password scp -o User=username -o StrictHostKeyChecking=no src dst:/path

1

Hmmm, mungkin opsi lain adalah menggunakan sesuatu seperti sshfs (ada juga sshfs untuk Mac). Setelah router Anda dipasang, Anda dapat langsung menyalin file. Saya tidak yakin apakah itu berfungsi untuk aplikasi khusus Anda, tetapi itu adalah solusi yang bagus untuk tetap berguna.



Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.