SCP या SSH का उपयोग करके पायथन में एक दूरस्थ सर्वर पर फ़ाइल की प्रतिलिपि कैसे करें?


103

मेरे पास मेरी स्थानीय मशीन पर एक पाठ फ़ाइल है जो क्रोन में चलने वाले दैनिक पायथन स्क्रिप्ट द्वारा उत्पन्न होती है।

मैं उस कोड को थोड़ा सा जोड़ना चाहूंगा कि फ़ाइल SSH के ऊपर मेरे सर्वर पर सुरक्षित रूप से भेजी जाए।


1
कुछ इसी तरह पाया, यू देख सकते हैं stackoverflow.com/questions/11009308/...
JJ84

जवाबों:


55

आप scpबैश कमांड को कॉल कर सकते हैं (यह SSH पर फ़ाइलों की प्रतिलिपि बनाता है ) subprocess.run:

import subprocess
subprocess.run(["scp", FILE, "USER@SERVER:PATH"])
#e.g. subprocess.run(["scp", "foo.bar", "joe@srvr.net:/path/to/foo.bar"])

यदि आप उसी पायथन प्रोग्राम में फ़ाइल भेजना चाहते हैं, जिसे आप फ़ाइल खोलने के लिए उपयोग कर रहे ब्लॉक के subprocess.runबाहर कमांड को कॉल करना चाहते withहैं (या .close()फ़ाइल पर कॉल करें यदि आप उपयोग नहीं कर रहे हैं तो withब्लॉक), तो आप जानते हैं कि यह पायथन से डिस्क में प्रवाहित है।

आपको (स्रोत मशीन पर) जेनरेट करना होगा और (गंतव्य मशीन पर) ssh कुंजी को पहले से इंस्टॉल करना होगा, ताकि आपके सार्वजनिक ssh कुंजी (दूसरे शब्दों में, इसलिए आपकी स्क्रिप्ट पासवर्ड नहीं मांगे) ।


3
@CharlesDuffy: subprocess.check_call(['scp', srcfile, dest])Python 2.5 के बजाय इस्तेमाल किया जा सकता हैrc = Popen(..).wait(); if rc != 0: raise ..
jfs

1
जब ज़रुरत न हो तो ssh key जोड़ना एक अच्छा उपाय नहीं है। उदाहरण के लिए, यदि आपको एक बार संचार की आवश्यकता है, तो आप सुरक्षा कारणों से ssh कुंजी सेट नहीं करते हैं।
orezvani

150

पैरामिको लाइब्रेरी के साथ पायथन में ऐसा करने के लिए (यानी सबप्रोसेस के माध्यम से एसपीपी लपेटना नहीं) या ऐसा करना, आप कुछ इस तरह करेंगे:

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

(आप शायद अज्ञात मेजबानों, त्रुटियों, किसी भी निर्देशिका को आवश्यक बनाने के साथ सौदा करना चाहते हैं, और इसी तरह)।


14
पैरामिको में एक अच्छा sftp.put (स्वयं, स्थानीयपथ, रेमोटेपथ, कॉलबैक = कोई नहीं) फ़ंक्शन भी है, इसलिए आपको लिखना नहीं है, और प्रत्येक फ़ाइल को बंद करना है।
जिम कैरोल

6
मैं यह नोट करूंगा कि एसएफटीपी एससीपी के समान नहीं है।
द्रोपकर

4
@ डराकर सवाल एसएसएच के ऊपर भेजने के लिए फाइल मांगी। यही करता है।
टोनी मेयर

8
नोट: इस काम ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())को तुरंत करने के बाद बॉक्स से बाहर कर दें ssh
डोडा

1
दोस्तों, क्या सर्वर पासवर्ड का उपयोग करना सुरक्षित है? क्या निजी कुंजी का उपयोग करने की संभावना है?
Aysennoussi

32

आप शायद उपप्रोसेस मॉड्यूल का उपयोग करेंगे । कुछ इस तरह:

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

जहां destinationशायद रूप का है user@remotehost:remotepath। मेरे मूल उत्तर में कमजोरी की ओर इशारा करने के लिए @Charles Duffy का धन्यवाद, जिसने scp ऑपरेशन को निर्दिष्ट करने के लिए एक एकल स्ट्रिंग तर्क का उपयोग किया shell=True- जो रास्तों में व्हाट्सएप को संभाल नहीं पाएगा।

मॉड्यूल प्रलेखन में त्रुटि की जाँच के उदाहरण हैं जो आप इस ऑपरेशन के साथ संयोजन के रूप में करना चाहते हैं।

सुनिश्चित करें कि आपने उचित क्रेडेंशियल्स सेट किए हैं ताकि आप मशीनों के बीच एक अनअटेंडेड, पासवर्ड रहित scp कर सकें । इसके लिए पहले से ही एक स्टैकओवरफ्लो प्रश्न है


3
Subprocess.Popen का उपयोग करना सही चीज है। इसे एक सरणी के बजाय एक स्ट्रिंग पास करना (और शेल = ट्रू का उपयोग करना) गलत बात है, क्योंकि इसका मतलब है कि रिक्त स्थान के साथ फ़ाइल नाम सही तरीके से काम नहीं करते हैं।
चार्ल्स डफी

2
"sts = os.waitpid (p.pid, 0)" के बजाय, हम "sts = p.wait ()" का उपयोग कर सकते हैं।
db42

वहाँ इस प्रोटोकॉल के लिए प्रत्यक्ष अजगर एपीआई के साथ एक निष्पादन मुक्त तरीका है?
lpapp

1
subprocess.check_call(['scp', myfile, destination])पाइथन 2.5 (2006) के बाद से इस्तेमाल किया जा सकता है
jfs

@JFSebastian: हाँ, मैंने दिसंबर में इसकी जाँच की। मेरे उत्थान साबित करते हैं कि, कम से कम। :) हालांकि अनुवर्ती के लिए धन्यवाद।
lpapp

12

समस्या से निपटने के लिए अलग-अलग तरीके हैं:

  1. कमांड-लाइन प्रोग्राम लपेटें
  2. पायथन लाइब्रेरी का उपयोग करें जो SSH क्षमताओं को प्रदान करता है (जैसे - पैरामिको या ट्विस्टेड कोंच )

प्रत्येक दृष्टिकोण के अपने स्वयं के प्रश्न हैं। यदि आप "ssh", "scp" या "rsync" जैसे सिस्टम कमांड्स को लपेट रहे हैं, तो आपको पासवर्ड-कम लॉगिन सक्षम करने के लिए SSH कुंजियों को सेटअप करने की आवश्यकता होगी। आप Paramiko या किसी अन्य लाइब्रेरी का उपयोग करके किसी स्क्रिप्ट में पासवर्ड एम्बेड कर सकते हैं, लेकिन आपको प्रलेखन निराशा की कमी मिल सकती है, खासकर यदि आप SSH कनेक्शन की मूल बातें (जैसे - प्रमुख एक्सचेंज, एजेंट, आदि) से परिचित नहीं हैं। यह शायद यह कहे बिना जाता है कि एसएसएच कीज इस तरह के सामान के लिए पासवर्ड से लगभग बेहतर विचार हैं।

नोट: यदि आप SSH के माध्यम से फ़ाइलों को स्थानांतरित करने की योजना बनाते हैं, तो rsync को हराना मुश्किल है, खासकर अगर विकल्प सादा पुराना scp है।

मैंने Paramiko का उपयोग सिस्टम कॉल को बदलने के लिए एक आंख के साथ किया है, लेकिन अपने उपयोग में आसानी और तत्काल परिचितता के कारण खुद को लिपटे हुए कमांडों में वापस पाया। आप अलग हो सकते हैं। मैंने कुछ समय पहले एक बार शंख दिया था, लेकिन इसने मुझे अपील नहीं की।

यदि सिस्टम-कॉल पथ के लिए चयन किया जाता है, तो पायथन ऑस.सिस्टम या कमांड / सबप्रोसेस मॉड्यूल जैसे विकल्पों की एक सरणी प्रदान करता है। यदि संस्करण 2.4+ का उपयोग कर रहा हूं तो मैं सबप्रोसेस मॉड्यूल के साथ जाऊंगा।


1
जिज्ञासु: rsync बनाम scp पर कहानी क्या है?
आलोक

7

उसी समस्या तक पहुँच गए, लेकिन "हैकिंग" या कमांड लाइन का अनुकरण करने के बजाय:

इसका जवाब यहां मिला ।

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

1
नोट - यह scp पैकेज पर निर्भर करता है। दिसंबर 2017 तक, उस पैकेज का नवीनतम अपडेट 2015 में था और संस्करण संख्या 0.1.x है। निश्चित नहीं कि मैं इस निर्भरता को जोड़ना चाहूंगा।
चक

2
इसलिए, यह अब 2018 है और हो सकता है कि उन्होंने संस्करण 0.11.0 जारी किया हो। तो, ऐसा लगता है कि SCPClient आखिरकार मरा नहीं है?
Adriano_Pinaffo

5

आप इस तरह से कुछ भी कर सकते हैं, साथ ही होस्ट की की चेकिंग को भी संभाल सकते हैं

import os
os.system("sshpass -p password scp -o StrictHostKeyChecking=no local_file_path username@hostname:remote_path")

4

fabric विज़ एसश फाइल अपलोड करने के लिए इस्तेमाल किया जा सकता है:

#!/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()

2

आप वासल पैकेज का उपयोग कर सकते हैं, जो बिल्कुल इसके लिए डिज़ाइन किया गया है।

आपको केवल वासल स्थापित करना और करना है

from vassal.terminal import Terminal
shell = Terminal(["scp username@host:/home/foo.txt foo_local.txt"])
shell.run()

इसके अलावा, यह आपको क्रेडेंशियल प्रमाणित करने से बचाएगा और उन्हें बार-बार टाइप करने की आवश्यकता नहीं है।


1

मैंने sshfs का उपयोग ssh के माध्यम से दूरस्थ निर्देशिका को माउंट करने के लिए किया है, और फाइलों को कॉपी करने के लिए शिल्ट किया है:

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

फिर अजगर में:

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

इस पद्धति का लाभ यह है कि आप डेटा को स्ट्रीम कर सकते हैं यदि आप स्थानीय रूप से कैशिंग करने के बजाय डेटा उत्पन्न कर रहे हैं और एक बड़ी फाइल भेज रहे हैं।


1

यदि आप SSL प्रमाणपत्र का उपयोग नहीं करना चाहते हैं तो यह कोशिश करें:

import subprocess

try:
    # Set scp and ssh data.
    connUser = 'john'
    connHost = 'my.host.com'
    connPath = '/home/john/'
    connPrivateKey = '/home/user/myKey.pem'

    # Use scp to send file from local to host.
    scp = subprocess.Popen(['scp', '-i', connPrivateKey, 'myFile.txt', '{}@{}:{}'.format(connUser, connHost, connPath)])

except CalledProcessError:
    print('ERROR: Connection to host failed!')

1

बाहरी संसाधन paramiko का उपयोग करना;

    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

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

स्थानीय नेटवर्क में अजगर कॉपी फ़ाइल देखें (linux -> linux)


0

एक बहुत ही सरल तरीका निम्नलिखित है:

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

कोई अजगर पुस्तकालय (केवल ओएस) की आवश्यकता नहीं है, और यह काम करता है, हालांकि इस विधि का उपयोग करने के लिए एक और ssh क्लाइंट पर निर्भर करता है। यदि किसी अन्य सिस्टम पर चलाया जाता है तो यह अवांछित व्यवहार हो सकता है।


-3

हैकी की तरह, लेकिन निम्नलिखित काम करना चाहिए :)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.