Pythonでscpする方法は?


158

Pythonでファイルをscpする最もPython的な方法は何ですか?私が知っている唯一のルートは

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

これはハックであり、Linuxライクなシステムの外部では機能しません。また、リモートホストにパスワードなしのSSHが設定されていない限り、パスワードプロンプトを回避するためにPexpectモジュールの支援が必要です。

Twistedを知っていますがconch、低レベルのsshモジュールを介してscpを自分で実装することは避けたいと思います。

paramikoSSHとSFTPをサポートするPythonモジュールであるを知っています。ただし、SCPはサポートされていません。

背景:SFTPはサポートしていませんが、SSH / SCPはサポートしているルーターに接続しているため、SFTPは選択できません。

編集:これはSCPまたはSSHを使用してPythonでファイルをリモートサーバーにコピーする方法の複製ですか?ただし、その質問では、Python内からのキーを処理するscp固有の回答は提供されません。私はある種のコードを実行する方法を望んでいます

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

回答:


106

ParamikoのPython scpモジュールを試してください。使い方はとても簡単です。次の例を参照してください。

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

次に、scp.get()またはscp.put()を呼び出してSCP操作を実行します。

SCPClientコード


3
そのモジュールが実際にparamikoを使用しないことを除いて、結局のところ、* nixでのみ機能scpするscpコマンドラインを実際に呼び出すのは、多くのコードです。
Nick Bastin

8
同意すると、ソースコードに表示されるのは、scp -torまたはscp -f(このサーバー側の目的で存在する「to」および「from」モード)へのリモート呼び出しです。これは本質的にscpの動作方法です。サーバーに存在するscpの別のコピーに依存しています。この記事はそれを非常によく説明しています:blogs.oracle.com/janp/entry/how_the_scp_protocol_works
laher

8
この解決策は、2つの警告で私にimport paramiko from scp import SCPClient役立ちました:1.これらは私が使用したインポート文です:2.以下はscp.get()コマンドの例です:scp.get(r'/nfs_home/appers/xxxx/test2.txt', r'C:\Users\xxxx\Desktop\MR_Test')
Chris Nielsen

これはうまく機能するだけでなく、SSHキーが存在する場合はそれを利用します。
Marcel Wilson

このlibはPyPIからもインストールできることに注意してくださいpip install scp
Andrew B.

15

Pexpectソースコード)を試してみてください。これにより、パスワードのインタラクティブなプロンプトを処理できます。

メインWebサイトからの使用例(ftpの例)の抜粋を以下に示します。

# 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

paramikoをチェックすることもできます。(まだ)scpモジュールはありませんが、sftpを完全にサポートしています。

[編集]申し訳ありませんが、paramikoについて言及している行を逃しました。次のモジュールは、paramikoのscpプロトコルの実装です。paramikoやconch(私がpythonで知っている唯一のssh実装)を使用したくない場合は、これを作り直して、パイプを使用して通常のsshセッションで実行できます。

paramikoのscp.py


添付のソリューションは、sftpdを実行していない場合でも、sshdを実行している任意のマシンにファイルを安全に転送しますか?それがまさに私が探しているものですが、コメントからはこれがsftpをscp風のファサードにラップしているだけなのかわかりません。
Michael Gundlach、

2
これは、sshdを実行している任意のマシンでファイルを転送します。これには、PATHにscpが含まれます(scpはssh仕様の一部ではありませんが、かなり一般的です)。これはサーバー上で「scp -t」を呼び出し、scpプロトコルを使用してファイルを転送します。これはsftpとは関係ありません。
JimB 2008

1
opensshのscpの実装をモデルとして使用しているため、他のバージョンでの動作が保証されていないことに注意してください。sshdの一部のバージョンでは、sftpと基本的に同じであるscp2プロトコルも使用する場合があります。
JimB 2008

この質問をご覧ください:stackoverflow.com/questions/20111242/…paramiko がサブプロセスを使用しているのか、それともソケットのような他のものを使用しているのかと思います。クローン/フォークの問題が原因で、subprocess.check_output( 'ssh blah@blah.com "cat / data / file *")を使用してメモリの問題が発生し、paramikoに同じ問題があるかどうか疑問に思っていますか?
ポール

1
@Paul:paramikoはサブプロセスを使用しないため、同じ問題は発生しません。
JimB 2013年

9

正解が見つかりませんでした。この「scp.Client」モジュールは存在しません。代わりに、これは私に適しています:

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

win32にputtyをインストールすると、pscp(putty scp)が得られます。

したがって、win32でもos.systemハックを使用できます。

(そして、キー管理にputty-agentを使用できます)


申し訳ありませんが、これは単なるハックです(ただし、Pythonクラスでラップできます)。


'nix oneが機能する唯一の理由は、パス上にSCPがあることです。ブラウアが指摘するように、それを修正するのはそれほど難しいことではありません。+1
ojrac 2008年

6

パッケージサブプロセスとコマンド呼び出しを使用して、シェルからscpコマンドを使用できます。

from subprocess import call

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

2
これは、質問者が述べた基本的なケースとどう違うのですか?はい、サブプロセスがより良いos.systemよりもですが、どちらの場合には、それは外のLinuxライクなシステムを動作しない、などのパスワードプロンプト、との問題を持っている
FOON

5

今日の時点で、最良のソリューションはおそらく 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
こんにちは。あなたはAsyncSSHが最高であると主張していますが、この主張を支持するために声明や2を述べることができますか?たぶん、それをscp()と区別したり、ユースケースにとってどのように重要だったりしたのでしょう。(これは、コードが大幅に少ないことを意味します
Scott Prive

2
@Crossfit_and_Beerこんにちは。だから私は「おそらく最高だ」と言った、私は誰にでも判断を任せるだろう:)私は今のところ、AsyncSSHを他のライブラリと比較する時間があまりない。しかし、非常に迅速に:使い方は簡単で、非同期であり、保守されており、メンテナーは非常に素晴らしく、便利で、非常に完全で、十分に文書化されています。
ロイック

5

見てい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
もっと具体的に教えていただけますか?
Nick T

4

この質問が出されてからしばらく経ち、その間、これを処理できる別のライブラリが登場しました。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)

Plumbumで秘密鍵のパスフレーズを入力するにはどうすればよいですか?p
ekta 2014年

@ekta:コマンドラインでそれを要求されます。あなたがあなた自身のコードからそれを提供したいのであれば、plumbumのAPIがこれをサポートするとは思わない。ただし、plumbumはにSshMachineアクセスできますssh-agent。そのため、毎回入力するのを避けたい場合は、それが1つの方法です。また、plumbumのgithubページで機能リクエストを提出することもできます。
pmos

2

* nixを使用している場合は、sshpassを使用できます

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

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

自分のソリューションが優れている理由を説明するコメントにコメントを追加し、読者がそれを他の利用可能なソリューションと比較するのに役立ちます。コードを投稿するだけでは、学習者がより良い解決策を認識する方法を常に理解できるとは限りません。
ブライアントンプセット-汤莱恩

これはSCPではなくSFTPです。
Martin Prikryl、

1

うーん、おそらく別のオプションはsshfs(Macにもsshfsがあります)のようなものを使用することです。ルーターがマウントされたら、ファイルを完全にコピーできます。それがあなたの特定のアプリケーションで機能するかどうかはわかりませんが、便利に保つための良い解決策です。



弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.