【问题标题】:Run script with arguments via ssh with at command from python script使用 python 脚本中的 at 命令通过 ssh 运行带有参数的脚本
【发布时间】:2016-07-28 05:08:28
【问题描述】:

我有一个 python 程序,它需要通过 ssh 在远程系统上调用一个脚本。

这个 ssh 调用需要在指定的日期发生(一次),这可以通过 linux at 命令完成。

我可以使用我的 python 程序中的os 模块或subprocess 模块来调用这两个外部 bash 命令。将某些参数传递给远程脚本时会出现问题。

除了在以后远程运行之外,我希望调用的 (bash) 脚本还需要传递几个参数,这些参数是我希望传递给脚本的 python 变量。

user="user@remote"
arg1="argument with spaces"
arg2="two"
cmd="ssh "+user+"' /home/user/path/script.sh "+arg1+" "+arg2+"'" 
os.system(cmd)

其中一个参数是一个包含空格但理想情况下作为单个参数传递的字符串;

例如:

./script.sh "Argument with Spaces" 其中 $1 等于 "Argument with Spaces"

我尝试了在 python 和字符串本身中转义双引号和单引号的各种组合,以及在整个 ssh 命令周围使用重音符号。最成功的版本根据需要使用参数调用脚本,但忽略 at 命令并立即运行。

在 python 中是否有一个干净的方法来完成这个?

【问题讨论】:

    标签: python bash ssh at-job


    【解决方案1】:

    新答案

    既然您编辑了您的问题,您可能应该使用格式字符串

    cmd = '''ssh {user} "{cmd} '{arg0}' '{arg1}'"'''.format(user="user@remote",cmd="somescript",arg0="hello",arg2="hello world")
    print cmd
    

    旧答案

    我认为您可以使用-c 开关和ssh 在远程机器上执行一些代码 (ssh user@host.net -c "python myscript.py arg1 arg2")

    或者我需要更多,所以我使用这个 paramiko 包装类(你需要安装 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:pass@ip'")
            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()
    

    你可以如下使用它

    client = SshClient("username:password@host.net")
    result = client.execute("python something.py cmd1 cmd2")
    print result
    
    result2 = client.execute("cp some_file /etc/some_file",sudo=True)
    print result2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-26
      • 1970-01-01
      • 2014-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-13
      相关资源
      最近更新 更多