Python으로 ssh를 통해 명령 수행


136

파이썬에서 일부 명령 줄 명령을 자동화하는 스크립트를 작성 중입니다. 현재 전화를 걸고 있습니다.

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

그러나 원격 컴퓨터에서 일부 명령을 실행해야합니다. 수동으로 ssh를 사용하여 로그인 한 다음 명령을 실행합니다. 파이썬에서 이것을 어떻게 자동화합니까? 원격 컴퓨터에 (알려진) 비밀번호로 로그인해야하므로 사용할 수 없습니다. 사용해야 cmd = ssh user@remotehost할 모듈이 있는지 궁금합니다.

답변:


201

나는 당신에게 paramiko 를 참조 할 것입니다

이 질문을

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

3
여기에서의 가정은 paramiko가 (open) ssh만큼 안전하다는 것입니다. 그렇습니까?
user239558

1
ssh 키를 교환하면 어떻게 되나요?
Ardit

19
SSH 키를 사용하는 경우 먼저 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())하고 마지막으로 ssh..connect(hostname=host, username=user, pkey=k).
Scott Prive

7
Paramiko (전문가는 아님)의 오랜 사용자로서 Paramiko의 사용을 제안 할 수 있지만 사용 사례와 학습하고자하는 금액을 고려해야합니다. Paramiko는 매우 저수준이므로 사용중인 코드를 완전히 이해하지 않고도 "명령 실행 도우미 기능"을 만드는 함정에 쉽게 빠질 수 있습니다. 그것은 당신이 def run_cmd(host, cmd):처음에 원하는 것을 하는 것을 디자인 할 수 있다는 것을 의미 하지만, 당신의 요구는 진화합니다. 새로운 유스 케이스에 대한 헬퍼를 변경하면 기존의 기존 사용법의 동작이 변경됩니다. 그에 따라 계획하십시오.
Scott Prive

3
알 수없는 호스트 오류의 경우 다음을 수행하십시오. ssh.set_missing_host_key_policy (paramiko.AutoAddPolicy ()) before
Nemo

49

또는 commands.getstatusoutput을 사용할 수 있습니다 .

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

광범위하게 사용했으며 훌륭하게 작동합니다.

Python 2.6 이상에서는을 사용하십시오 subprocess.check_output.


4
멋진 간단한 내장 방법으로 +1 현재 설정에서 파이썬 라이브러리를 추가하고 싶지 않으므로 귀하의 제안도 매우 간단합니다.
Philip Kearns

3
원격 호스트가 암호가없는 ssh로 설정되어 있는지 확인하십시오. 그렇지 않은 경우 인증 관리를 위해 다른 작업을 수행해야합니다
powerrox

subprocess.check_output-훌륭한 솔루션!
Tim S.

2
@powerrox 그 "다른 것들"은 무엇입니까?
ealeon

2
@TimS. 설정에 적절한 방법으로 인증 처리를 포함해야 할 수도 있습니다. 프롬프트에서 비밀번호를 입력 할 것으로 예상했습니다. 그런 다음 다른 솔루션과 함께이 스레드가 있습니다 : unix.stackexchange.com/questions/147329/…
powerrox

29

Fabric을 보셨습니까 ? 파이썬을 사용하여 SSH를 통해 모든 종류의 원격 작업을 수행 할 수 있습니다.


18

나는 paramiko가 너무 낮은 수준이라는 것을 알았고 Fabric은 라이브러리로 사용하기에 특히 적합하지 않기 때문에 paramiko를 사용하여 약간 더 멋진 인터페이스를 구현하는 spur 를 구성했습니다.

import spur

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

쉘 내부에서 실행해야하는 경우 :

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

2
나는 시도하기로 결정했다 spur. 추가 쉘 명령을 생성하면 다음과 같이 종료됩니다. which 'mkdir'> / dev / null 2> & 1; 에코 $ ?; exec 'mkdir' '-p' '/ data / rpmupdate / 20130207142923'. 나는 또한 평원에 접근하고 싶습니다 exec_command. 백그라운드 작업을 실행할 수있는 기능이 없습니다 nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &. 예를 들어, 템플릿을 사용하여 zsh 스크립트 (rpmbuildpackages)를 생성 한 다음 컴퓨터에서 계속 실행합니다. 아마도 그러한 백그라운드 작업을 모니터링하는 능력도 좋을 것입니다 (~ / .spur에 PID 저장).
davidlt

1
spur분명히 유닉스 시스템에서만 작동합니다 termios. 아무도 좋은 Windows 용 라이브러리를 알고 있습니까?
Gabriel

사전 컴파일 된 설치 프로그램 을 사용하는 경우 paramiko 및 spur를 설치할 수 있습니다. 방금 직접
해봤습니다

@Gabriel : 최신 릴리스 중 하나가 Windows에 대한 지원을 개선해야합니다. 여전히 작동하지 않으면 문제를 자유롭게여십시오.
Michael Williamson

@davidlt :를 구성 할 때 SshShell쉘 유형을 설정하는 옵션이 있습니다. 를 전달하여 최소 쉘을 사용 shell_type=spur.ssh.ShellTypes.minimal하면 원시 명령 만 전송됩니다. 백그라운드 작업을 구현하면 Spur의 범위를 약간 벗어난 것처럼 느껴지지만 쉘을 호출하여 설명한 명령을 실행할 수 있어야합니다 (예 :) shell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"].
Michael Williamson

18

간단하게 유지하십시오. 라이브러리가 필요하지 않습니다.

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
하위 프로세스는 자동화의 스위스 군용 칼입니다. 그런 다음 Python을 쉘 스크립트, sed, awk, grep과 같은 끝없는 가능성과 결합 할 수 있습니다. 예, 모두 파이썬으로 할 수 있지만 파이썬 어딘가에서 grep을 실행하는 것은 좋지 않습니다.
Ronn Macc

12
ssh 명령이 암호를 요구하면 파이썬 파일에서 어떻게 암호를 제공합니까?
BeingSuman

1
@BeingSuman SSH 키 인증을 사용할 수 있습니다. 당신이 이미 알아 낸 것 같아요.
mmrbulbul

9

모두 paramiko를 사용하여 이미 언급 (권장) 했으며 한 번에 여러 명령을 실행할 수있는 파이썬 코드 (API 하나)를 공유하고 있습니다.

다른 노드에서 명령을 실행하려면 다음을 사용하십시오. Commands().run_cmd(host_ip, list_of_commands)

명령 중 하나라도 실행되지 않으면 실행을 중지 한 TODO가 표시됩니다. 어떻게 해야할지 모르겠습니다. 당신의 지식을 공유하십시오

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

감사합니다!


4

나는 paramiko 를 무리 (좋은)와 pxssh (또한 좋은)를 사용했습니다. 어느 쪽이든 추천합니다. 그것들은 조금 다르게 작동하지만 사용법이 비교적 겹칩니다.


4
pxssh에 대한 링크는 과거로의 멋진 여정입니다.
Oben Sonne

3

paramiko 는 추가 라인을 추가 한 후 마침내 나를 위해 일했습니다.

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 패키지가 설치되어 있는지 확인하십시오. 솔루션의 원래 소스 : 소스


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

완벽하게 작동합니다 ...

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

받아 들여진 대답이 효과가 없었습니다.

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
...

또는 sshpass 를 사용할 수 있습니다 .

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

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


0

유형 주석과 몇 가지 사소한 특수 효과 (SFTP, md5 등을 다시 연결)를 제공하는 spurplus우리가 개발 한 래퍼를 살펴보십시오 . https://pypi.org/project/spurplus/spur


1
래퍼 주위 래퍼 주위 래퍼 .. nice :)
Alex R

배포 스크립트를 단순하게 유지하려면 기본 도구가 단순 / 추상적이라고 의심합니다. 지금까지 유출 된 추상화는 관찰되지 않았습니다.
marko.ristin

0

로그인하는 장치에 따라 사용자에게 명령을 입력하도록 요청합니다
. 아래 코드는 PEP8online.com에서 확인합니다.

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

아래 예는 호스트 이름, 사용자 이름, 비밀번호 및 포트 번호에 대한 사용자 입력을 원하는 경우를위한 것입니다.

  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
더 나은 형식으로 2 일 전에 답변을 다시 게시하는 대신 이전 답변을 수정하고 형식을 개선하지 않는 이유는 무엇입니까?
snakecharmerb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.