Python ile ssh üzerinde komutlar gerçekleştirme


136

Python'da bazı komut satırı komutlarını otomatikleştirmek için bir komut dosyası yazıyorum. Şu anda telefon görüşmeleri yapıyorum:

cmd = "some unix command"
retcode = subprocess.call(cmd,shell=True)

Ancak uzaktaki bir makinede bazı komutları çalıştırmam gerekiyor. El ile, ssh kullanarak oturum ve komutları çalıştırmak. Python'da bunu nasıl otomatikleştirebilirim? Uzak makineye (bilinen) bir şifre ile giriş yapmam gerekiyor, bu yüzden sadece kullanamıyorum cmd = ssh user@remotehost, kullanmam gereken bir modül olup olmadığını merak ediyorum?

Yanıtlar:


201

Seni paramiko'ya yönlendireceğim

bkz bu soruyu

ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(cmd_to_execute)

3
Buradaki varsayım, paramiko'nun (açık) ssh kadar güvenli olduğudur. Bu mu?
user239558

1
ssh anahtarları değiştirilirse ne olur?
Ardit

19
SSH anahtarları kullanıyorsanız, önce EITHER: k = paramiko.RSAKey.from_private_key_file(keyfilename)OR k = paramiko.DSSKey.from_private_key_file(keyfilename)THEN ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ve son olarak anahtar dosyasını hazırlayın ssh..connect(hostname=host, username=user, pkey=k).
Scott Prive

7
Paramiko'yu uzun süredir kullanan bir kullanıcı olarak (ancak bir uzman değil), Paramiko'yu kullanmanızı önerebilirim, ancak kullanım durumlarınızı ve ne kadar öğrenmek istediğinizi düşünmelisiniz. Paramiko çok düşük seviyededir ve kullandığınız kodu tam olarak anlamadan bir "komut çalıştırma yardımcı işlevi" oluşturduğunuz bir tuzağa kolayca düşebilirsiniz. Bu def run_cmd(host, cmd):, ilk başta istediğinizi yapan bir tasarım söyleyebileceğiniz anlamına gelir , ancak ihtiyaçlarınız gelişir. Sonunda, eski kullanımın davranışını değiştiren yeni kullanım durumu için yardımcıyı değiştirirsiniz. Buna göre planlayın.
Scott Prive

3
Bilinmeyen ana bilgisayar hatası için şunları yapın: ssh.set_missing_host_key_policy (paramiko.AutoAddPolicy ()) önce
Nemo

49

Veya sadece commands.getstatusoutput komutunu kullanabilirsiniz :

   commands.getstatusoutput("ssh machine 1 'your script'")

Çok kullandım ve harika çalışıyor.

Python 2.6+ sürümünde kullanın subprocess.check_output.


4
Güzel basit bir yerleşik yöntem için +1. Şu anki kurulumumda Python kitaplıkları eklemek istemiyorum, bu yüzden öneriniz değerli, çok basit.
Philip Kearns

3
uzak ana bilgisayarınızın parolasız ssh için ayarlandığından emin olun, eğer değilse, kimlik doğrulamasını yönetmek için başka şeyler yapmanız gerekir
powerrox 21

subprocess.check_output - harika bir çözüm!
Tim

2
@powerrox "diğer şeyler" neler?
ealeon

2
@TimS. kurulumunuz için uygun olan yöntemlerle kimlik doğrulama işlemlerini dahil etmeniz gerekebilir. Komut istemine şifre girmeyi bekledim. o zaman diğer çözümler ile bu konu var: unix.stackexchange.com/questions/147329/…
powerrox

29

Fabric'e bir göz attın mı? Python kullanarak SSH üzerinden her türlü uzak şeyi yapmanızı sağlar.


18

Paramiko'nun biraz çok düşük seviyeli olduğunu gördüm ve Kumaş bir kütüphane olarak kullanılmaya uygun değildi, bu yüzden biraz daha hoş bir arayüz uygulamak için paramiko kullanan spur adlı kendi kütüphanemi bir araya getirdim:

import spur

shell = spur.SshShell(hostname="localhost", username="bob", password="password1")
result = shell.run(["echo", "-n", "hello"])
print result.output # prints hello

Bir kabuğun içinde koşmanız gerekiyorsa:

shell.run(["sh", "-c", "echo -n hello"])

2
Denemeye karar verdim spur. Ek kabuk komutları oluşturursunuz ve bununla sonuçlanır: hangi 'mkdir'> / dev / null 2> & 1; echo $ ?; exec 'mkdir' '-p' '/ data / rpmupdate / 20130207142923'. Bir ovaya da erişmek istiyorum exec_command. Ayrıca arka plan görevleri çalıştırma yeteneğine eksik: nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &. Örneğin, şablonu kullanarak bir zsh komut dosyası (rpmbuildpackages) oluşturuyorum ve sonra sadece makinede çalışmasını bırakıyorum. Belki bu tür arka plan işlerini izleme yeteneği de iyi olurdu (bazı ~ / .spur'da PID tasarrufu).
davidlt

1
spurGörünüşe göre sadece unix sistemlerde çalışır, bağımlılığına neden olur termios. Windows için iyi bir kütüphane bilen var mı?
Gabriel

Tamamen doğru değil: önceden derlenmiş bir yükleyici kullanırsanız , paramiko ve mahmuz kurabilirsiniz. Sadece kendim yaptım ...
ravemir

@ Gabriel: son sürümlerden birinin Windows üzerinde geliştirilmiş desteği olmalıdır. Hala çalışmıyorsa, lütfen bir sorun açmaktan çekinmeyin.
Michael Williamson

@davidlt: an oluştururken SshShell, artık kabuk türünü ayarlama seçeneği vardır. İçeri aktarılarak minimal bir kabuk kullanılıyorsa shell_type=spur.ssh.ShellTypes.minimal, yalnızca raw komutu gönderilir. Arka plan görevlerini uygulamak doğrudan Spur için biraz kapsam dışı hisseder, ancak bir kabuk çağırarak tanımladığınız komutu çalıştırabilmeniz gerekir shell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"].
Michael Williamson

18

Basit tutun. Kütüphaneye gerek yok.

import subprocess

subprocess.Popen("ssh {user}@{host} {cmd}".format(user=user, host=host, cmd='ls -l'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

1
Alt süreç, otomasyonda İsviçre çakısıdır. Daha sonra Python'u kabuk komut dosyaları, sed, awk, grep gibi sonsuz olasılıklarla birleştirebilirsiniz. Evet hepiniz Python yapabilirsiniz, ama sadece python bir yerde bir grep çalıştırmak için iyi olmaz - iyi.
Ronn Macc

12
ssh komutlarınız şifre isterse, bunu Python dosyasında nasıl sağlarsınız?
BeingSuman

1
@BeingSuman Bunun için SSH anahtar kimlik doğrulamasını kullanabilirsiniz. Sanırım bunu zaten çözmüşsün.
mmrbulbul

9

Hepsi paramiko kullanarak zaten belirtti (tavsiye etti) ve ben sadece bir seferde birden fazla komut yürütmek için izin verecek bir python kodu (API diyebilirim) paylaşıyorum.

farklı düğüm kullanımında komutları yürütmek için: Commands().run_cmd(host_ip, list_of_commands)

Herhangi bir komutun yürütülememesi durumunda yürütmeyi durdurmak için tuttuğum bir TODO göreceksiniz, nasıl yapılacağını bilmiyorum. lütfen bilgini paylaş

#!/usr/bin/python

import os
import sys
import select
import paramiko
import time


class Commands:
    def __init__(self, retry_time=0):
        self.retry_time = retry_time
        pass

    def run_cmd(self, host_ip, cmd_list):
        i = 0
        while True:
        # print("Trying to connect to %s (%i/%i)" % (self.host, i, self.retry_time))
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(host_ip)
            break
        except paramiko.AuthenticationException:
            print("Authentication failed when connecting to %s" % host_ip)
            sys.exit(1)
        except:
            print("Could not SSH to %s, waiting for it to start" % host_ip)
            i += 1
            time.sleep(2)

        # If we could not connect within time limit
        if i >= self.retry_time:
            print("Could not connect to %s. Giving up" % host_ip)
            sys.exit(1)
        # After connection is successful
        # Send the command
        for command in cmd_list:
            # print command
            print "> " + command
            # execute commands
            stdin, stdout, stderr = ssh.exec_command(command)
            # TODO() : if an error is thrown, stop further rules and revert back changes
            # Wait for the command to terminate
            while not stdout.channel.exit_status_ready():
                # Only print data if there is data to read in the channel
                if stdout.channel.recv_ready():
                    rl, wl, xl = select.select([ stdout.channel ], [ ], [ ], 0.0)
                    if len(rl) > 0:
                        tmp = stdout.channel.recv(1024)
                        output = tmp.decode()
                        print output

        # Close SSH connection
        ssh.close()
        return

def main(args=None):
    if args is None:
        print "arguments expected"
    else:
        # args = {'<ip_address>', <list_of_commands>}
        mytest = Commands()
        mytest.run_cmd(host_ip=args[0], cmd_list=args[1])
    return


if __name__ == "__main__":
    main(sys.argv[1:])

Teşekkür ederim!


4

Ben kullandım paramiko bir demet (güzel) ve pxssh (aynı zamanda güzel). Ben de tavsiye ederim. Biraz farklı çalışırlar, ancak kullanımda nispeten büyük bir örtüşmeye sahiptirler.


4
Pxssh bağlantısı zaman içinde güzel bir yolculuktur.
Oben Sonne

3

paramiko nihayet benim için gerçekten önemli olan ek satır ekledikten sonra çalıştı (satır 3):

import paramiko

p = paramiko.SSHClient()
p.set_missing_host_key_policy(paramiko.AutoAddPolicy())   # This script doesn't work for me unless this line is added!
p.connect("server", port=22, username="username", password="password")
stdin, stdout, stderr = p.exec_command("your command")
opt = stdout.readlines()
opt = "".join(opt)
print(opt)

Paramiko paketinin kurulu olduğundan emin olun. Çözümün orijinal kaynağı: Kaynak


1
#Reading the Host,username,password,port from excel file
import paramiko 
import xlrd

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

loc = ('/Users/harshgow/Documents/PYTHON_WORK/labcred.xlsx')
wo = xlrd.open_workbook(loc)
sheet = wo.sheet_by_index(0)
Host = sheet.cell_value(0,1)
Port = int(sheet.cell_value(3,1))
User = sheet.cell_value(1,1)
Pass = sheet.cell_value(2,1)

def details(Host,Port,User,Pass):
    ssh.connect(Host, Port, User, Pass)
    print('connected to ip ',Host)
    stdin, stdout, stderr = ssh.exec_command("")
    stdin.write('xcommand SystemUnit Boot Action: Restart\n')
    print('success')

details(Host,Port,User,Pass)

1

Mükemmel çalışıyor...

import paramiko
import time

ssh = paramiko.SSHClient()
#ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('10.106.104.24', port=22, username='admin', password='')

time.sleep(5)
print('connected')
stdin, stdout, stderr = ssh.exec_command(" ")

def execute():
       stdin.write('xcommand SystemUnit Boot Action: Restart\n')
       print('success')

execute()

1

Kabul edilen cevap benim için çalışmadı, işte bunun yerine kullandım:

import paramiko
import os

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# ssh.load_system_host_keys()
ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
ssh.connect("d.d.d.d", username="user", password="pass", port=22222)

ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -alrt")
exit_code = ssh_stdout.channel.recv_exit_status() # handles async exit error 

for line in ssh_stdout:
    print(line.strip())

total 44
-rw-r--r--.  1 root root  129 Dec 28  2013 .tcshrc
-rw-r--r--.  1 root root  100 Dec 28  2013 .cshrc
-rw-r--r--.  1 root root  176 Dec 28  2013 .bashrc
...

Alternatif olarak, sshpass kullanabilirsiniz :

import subprocess
cmd = """ sshpass -p "myPas$" ssh user@d.d.d.d -p 22222 'my command; exit' """
print( subprocess.getoutput(cmd) )

Kaynaklar:
1. https://github.com/onyxfish/relay/issues/11
2. https://stackoverflow.com/a/61016663/797495


0

Göz at spurplus, biz etrafında gelişen bir sarmalayıcı spurtürü açıklamaları ve bazı küçük hile sağlar (SFTP'yi reconnecting, md5 vb .): Https://pypi.org/project/spurplus/


1
bir sarıcı bir sarıcı etrafında bir sarıcı .. güzel :)
Alex R

Dağıtım komut dosyalarınızı önemsiz tutmak istiyorsanız, temel araçların yeterince basit / soyut olduğundan şüpheliyim. Şimdiye kadar sızdıran soyutlamalar gözlemlemedik.
marko.ristin

0

Kullanıcıdan giriş yaptıkları cihaza göre komutu girmesini istemek.
Aşağıdaki kod PEP8online.com tarafından doğrulanmıştır.

import paramiko
import xlrd
import time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
loc = ('/Users/harshgow/Documents/PYTHON_WORK/labcred.xlsx')
wo = xlrd.open_workbook(loc)
sheet = wo.sheet_by_index(0)
Host = sheet.cell_value(0, 1)
Port = int(sheet.cell_value(3, 1))
User = sheet.cell_value(1, 1)
Pass = sheet.cell_value(2, 1)

def details(Host, Port, User, Pass):
    time.sleep(2)
    ssh.connect(Host, Port, User, Pass)
    print('connected to ip ', Host)
    stdin, stdout, stderr = ssh.exec_command("")
    x = input('Enter the command:')
    stdin.write(x)
    stdin.write('\n')
    print('success')

details(Host, Port, User, Pass)

0

Aşağıdaki örnekte, anasistem adı, kullanıcı adı, parola ve bağlantı noktası no.

  import paramiko

  ssh = paramiko.SSHClient()

  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())



  def details():

  Host = input("Enter the Hostname: ")

  Port = input("Enter the Port: ")

  User = input("Enter the Username: ")

  Pass = input("Enter the Password: ")

  ssh.connect(Host, Port, User, Pass, timeout=2)

  print('connected')

  stdin, stdout, stderr = ssh.exec_command("")

  stdin.write('xcommand SystemUnit Boot Action: Restart\n')

  print('success')

  details()

5
Daha iyi biçimlendirmeyle yanıtınızı iki gün önce yeniden yayınlamak yerine, neden eski cevabı düzenlemeyip biçimlendirmesini iyileştirmeyesiniz?
snakecharmerb
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.