从shell命令中获取输出,该命令在后台运行

时间:2015-04-01 12:53:41

标签: python shell ssh

我在this post中看到了一些有用的信息,说明如果使用subprocess从中检索输出,如何无法在后台运行流程。问题是......这正是我想要做的!

我有一个脚本通过ssh将命令丢弃到各个主机,我不想在开始下一个之前等待每个主机完成。理想情况下,我可以这样:

for host in hostnames:
  p[host] = Popen(["ssh", mycommand], stdout=PIPE, stderr=PIPE)
  pout[host], perr[host] = p[host].communicate()

mycommand需要很长时间的情况下,所有主机同时运行mycommand。就像现在一样,似乎整个ssh命令在开始下一个命令之前完成。由于我正在捕获输出,这是(根据我之前链接的帖子),对吧?除了cat输出到文件并稍后读取输出之外,还有一种不错的方法可以在各种主机上并行发生这些事情吗?

2 个答案:

答案 0 :(得分:1)

您可能需要使用fabric

  

Fabric是一个Python(2.5-2.7)库和命令行工具,用于简化SSH在应用程序部署或系统管理任务中的使用。

示例文件:

from fabric.api import run, env

def do_mycommand():
    my_command = "ls" # change to your command
    output = run(mycommand)
    print "Output of %s on %s:%s" % (mycommand, env.host_string, output)

现在要在所有主机上执行(host1,host2 ...是所有主机都去的地方):

fab -H host1,host2 ... do_mycommand

答案 1 :(得分:0)

您可以使用threads来实现并行性,并使用Queue以线程安全的方式检索结果:

import subprocess
import threading
import Queue

def run_remote_async(host, command, result_queue, identifier=None):
    if isinstance(command, str):
        command = [command]

    if identifier is None:
        identifier = "{}: '{}'".format(host, ' '.join(command))

    def worker(worker_command_list, worker_identifier):
        p = subprocess.Popen(worker_command_list,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
        result_queue.put((worker_identifier, ) + p.communicate())

    t = threading.Thread(target=worker,
            args=(['ssh', host] + command, identifier),
            name=identifier)
    t.daemon = True
    t.start()

    return t

然后,可能的测试用例可能如下所示:

def test():
    data = [('host1', ['ls', '-la']),
            ('host2', 'whoami'),
            ('host3', ['echo', '"Foobar"'])]
    q = Queue.Queue()
    for host, command in data:
        run_remote_async(host, command, q)
    for i in range(len(data)):
        identifier, stdout, stderr = q.get()
        print identifier
        print stdout

Queue.get()正在阻止,因此此时您可以在任务完成后收集一个接一个的结果。