2016-07-26 4 views
0

ssh를 통해 원격 시스템에서 스크립트를 호출해야하는 Python 프로그램이 있습니다.ssh를 통해 인수로 스크립트 실행하기 python 스크립트에서 at 명령으로

이 ssh 호출은 linux at 명령을 통해 수행 할 수있는 지정된 날짜에 발생해야합니다 (한 번).

파이썬 프로그램의 os 모듈 또는 subprocess 모듈 중 하나를 사용하여 이러한 외부 bash 명령어를 호출 할 수 있습니다. 특정 인수를 원격 스크립트에 전달할 때 문제가 발생합니다.

원격으로 실행되는 것 외에도 나중에 호출하려는 (bash) 스크립트에는 전달할 인수가 여러 개 필요합니다.이 인수는 스크립트에 전달하려는 Python 변수입니다.

user="[email protected]" 
arg1="argument with spaces" 
arg2="two" 
cmd="ssh "+user+"' /home/user/path/script.sh "+arg1+" "+arg2+"'" 
os.system(cmd) 

이러한 인수 중 하나는 공백을 포함하지만 이상적인 단일 인수로 전달되는 문자열입니다. 예를 들어

: $ 1 내가 파이썬과 문자열 자체와 전체 주위에 무덤 악센트의 사용 모두에서 단일 및 이중 따옴표를 이스케이프의 다양한 조합을 시도 "Argument with Spaces"

같다

./script.sh "Argument with Spaces" ssh 명령. 가장 성공적인 버전은 원하는대로 인수를 사용하여 스크립트를 호출하지만 at 명령은 무시하고 즉시 실행됩니다.

이것을 달성하기 위해 파이썬에는 깨끗한 방법이 있습니까?

답변

2

새 응답 당신은 아마 형식 문자열

cmd = '''ssh {user} "{cmd} '{arg0}' '{arg1}'"'''.format(user="[email protected]",cmd="somescript",arg0="hello",arg2="hello world") 
print cmd 

나는 당신이 -c를 사용할 수 있다고 생각 된 답을 사용해야 질문을 편집하는 것이 지금

ssh으로 전환하여 일부 코드를 실행하십시오.

client = SshClient("username:[email protected]") 
result = client.execute("python something.py cmd1 cmd2") 
print result 

result2 = client.execute("cp some_file /etc/some_file",sudo=True) 
print result2 
을 다음과 같이 다음을 사용할 수있는 원격 시스템

(ssh [email protected] -c "python myscript.py arg1 arg2")

는 양자 택일 나는 그래서이 paramiko 래퍼 클래스를 사용하는 것보다 더 필요

from contextlib import contextmanager 
import os 
import re 
import paramiko 
import time 


class SshClient: 
    """A wrapper of paramiko.SSHClient""" 
    TIMEOUT = 10 

    def __init__(self, connection_string,**kwargs): 
     self.key = kwargs.pop("key",None) 
     self.client = kwargs.pop("client",None) 
     self.connection_string = connection_string 
     try: 
      self.username,self.password,self.host = re.search("(\w+):(\w+)@(.*)",connection_string).groups() 
     except (TypeError,ValueError): 
      raise Exception("Invalid connection sting should be 'user:[email protected]'") 
     try: 
      self.host,self.port = self.host.split(":",1) 
     except (TypeError,ValueError): 
      self.port = "22" 
     self.connect(self.host,int(self.port),self.username,self.password,self.key) 
    def reconnect(self): 
     self.connect(self.host,int(self.port),self.username,self.password,self.key) 

    def connect(self, host, port, username, password, key=None): 
     self.client = paramiko.SSHClient() 
     self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
     self.client.connect(host, port, username=username, password=password, pkey=key, timeout=self.TIMEOUT) 

    def close(self): 
     if self.client is not None: 
      self.client.close() 
      self.client = None 

    def execute(self, command, sudo=False,**kwargs): 
     should_close=False 
     if not self.is_connected(): 
      self.reconnect() 
      should_close = True 
     feed_password = False 
     if sudo and self.username != "root": 
      command = "sudo -S -p '' %s" % command 
      feed_password = self.password is not None and len(self.password) > 0 
     stdin, stdout, stderr = self.client.exec_command(command,**kwargs) 
     if feed_password: 
      stdin.write(self.password + "\n") 
      stdin.flush() 

     result = {'out': stdout.readlines(), 
       'err': stderr.readlines(), 
       'retval': stdout.channel.recv_exit_status()} 
     if should_close: 
      self.close() 
     return result 

    @contextmanager 
    def _get_sftp(self): 
     yield paramiko.SFTPClient.from_transport(self.client.get_transport()) 

    def put_in_dir(self, src, dst): 
     if not isinstance(src,(list,tuple)): 
      src = [src] 
     print self.execute('''python -c "import os;os.makedirs('%s')"'''%dst) 
     with self._get_sftp() as sftp: 
      for s in src: 
       sftp.put(s, dst+os.path.basename(s)) 

    def get(self, src, dst): 
     with self._get_sftp() as sftp: 
      sftp.get(src, dst) 
    def rm(self,*remote_paths): 
     for p in remote_paths: 
      self.execute("rm -rf {0}".format(p),sudo=True) 
    def mkdir(self,dirname): 
     print self.execute("mkdir {0}".format(dirname)) 
    def remote_open(self,remote_file_path,open_mode): 
     with self._get_sftp() as sftp: 
      return sftp.open(remote_file_path,open_mode) 

    def is_connected(self): 
     transport = self.client.get_transport() if self.client else None 
     return transport and transport.is_active() 

을 (당신이 paramiko를 설치해야합니다)