【问题标题】:Using Twisted to run and return output from shell commands (find)使用 Twisted 运行并返回 shell 命令的输出(查找)
【发布时间】:2018-02-06 21:52:00
【问题描述】:

我尝试使用 Twisted 作为后端来允许用户使用 shell 命令搜索文件。

我遇到的问题是,当收到请求时,子进程会阻止新请求扭曲并将这些请求排队。这可以防止我取消之前的请求以运行新的请求。

我已经尝试了一些解决这个问题的方法,我发现这些解决方案包括 spawnprocess 和尝试使用 deferred。但是我无法找到返回输出的方法。任何帮助将不胜感激!

global child_pid
if child_pid is None:
    pass
else:
    for i in child_pid:
        try:
            i.kill()
        except Exception as e:
             pass

try:
    find_cmd = ("find '/var/log/' -type f -name '*.log' -newermt '2018-
        01-01 00:00:00' ! -newermt '2018-02-06 23:59:59'  -exec cat {} \+  2>&1")

    # run search command
    proc = subprocess.Popen(find_cmd, stdout=subprocess.PIPE,
        stderr=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
    # record pid of process so new requests can kill the previous 
    # subprocess
    child_pid.append(proc)

    # check for output until process is done
    output = ''
    while True:
        line = proc.stdout.readline()
        output += '\n' + line
        if line == '' or proc.poll() is not None:
            break
    return output
except Exception as e:
    return 'Error', False

编辑:

谢谢!我觉得我越来越近了。它不再阻塞了。不过我还是有点卡住了,我不知道为什么我花了这么长时间才弄清楚这一点……我读了这么多书,但我并没有陷入困境,我很沮丧,这可能没有帮助。

这是我目前所拥有的,可能会更好地了解我想要完成的工作:

from __future__ import print_function
from os import environ
from twisted.internet.protocol import ProcessProtocol
from twisted.internet import reactor

class Collector(ProcessProtocol):
    def __init__(self):
        self.output = ""
        self.error = False
    def connectionMade(self):
        self.received = []

    def childDataReceived(self, fd, data):
        self.received.append(data)

    def processExited(self, reason):
        if 'code 0' in reason:
            print('0')
            self.error = False
        else:
            print('1')
            self.error = True
        reactor.stop()


def process_query(commands):
    if len(commands) > 0:
        return commands, 'success', True
    return commands, 'fail', False

def run_shell_command(commands):
    proto = Collector()
    find = reactor.spawnProcess(
        proto,
        commands[0],
        commands,
        env=environ,
    )
    reactor.callLater(.5, find.signalProcess, b"KILL")
    return proto.output, True

def format_output(output, commands):
    output_list = []
    try:
        output_list = output.split('\n')
        output_list.append(commands)
        return ouptut_list, True
    except:
        return '', False


def run_command(commands):
    response = {}
    message = ''
    result = True

    # format and validate parameters
    formatted_commands, message, result = process_query(commands)
    # where result is pass or failure of the command and message is reason
    if not result:
        response['message'] = message
        response['result'] = result
        return response
    shell_output, result = run_shell_command(formatted_commands)
    # where result is pass or failure of the command
    if not result:
        response['message'] = 'Error'
        return response
    formatted_output, result = format_output(shell_output, formatted_commands)
    response['data'] = formatted_output
    response['result'] = result
    if not result:
        response['message'] = 'Error'
        return response
    if len(formatted_output) < 1:
        response['message'] = 'No output found'
        response['result'] = False
        return response
    return response


cmd = [b"find", b"/var/log",
        b"-type", b"f",
        b"-name", b"*.log",
        b"-newermt", b"2018-01-01 00:00:00",
        b"!", b"-newermt", b"2018-02-06 23:59:59",
        b"-exec", b"cat", b"{}", b"+"]

x = run_command(cmd)
print(x)
reactor.run()

我一直在阅读有关延期的文章,他们似乎可以帮助我......可能是这样的:

 def run_command(commands):
    response = {}
    message = ''
    result = True

    formatted_commands, message, result = process_query(commands)
    if not result:
        response['message'] = message
        response['result'] = result
        return response

    shell_output = utils.getProcessOutput(formatted_commands)
    shell_output.addCallback(format_output, formatted_commands)

    response['data'] = shell_output
    response['result'] = True
    return response

这不起作用,但感觉很接近。我完全迷路了。感谢您到目前为止的帮助!

【问题讨论】:

  • 我发布的答案的第一个版本(快速编辑)使用了 getProcessOutput。这是显而易见且简单的解决方案 - 除了您提到希望能够取消该进程,我将其读作“在完成之前杀死子进程”。如果你想要那样,不幸的是 getProcessOutput 没有帮助,因为它只给你结果,它没有给你任何杀死进程的方法。因此,使用自定义协议的 spawnProcess。杀死进程是一个重要的要求吗?
  • 您应该在您的程序中启用日志记录,以便当 Twisted 为您捕获异常并记录它时,您可以实际看到它。这可能表明您的 processExited 存在错误(您无法检查字符串是否在 reason 中)。此外,您似乎仍然没有正确使用 Deferreds。 Deferred 不是结果。它只是一个对象,您可以调用 addCallback(f) 以在某个时候调用 f(the_result)。将您想要对结果执行的操作的逻辑放入一个函数中,并将其作为回调添加到 Deferred。

标签: python linux twisted


【解决方案1】:
from __future__ import print_function
from os import environ
from twisted.internet.protocol import ProcessProtocol
from twisted.internet import reactor

class Collector(ProcessProtocol):
    def connectionMade(self):
        self.received = []

    def childDataReceived(self, fd, data):
        self.received.append(data)

    def processExited(self, reason):
        print(reason)
        reactor.stop()

proto = Collector()
find = reactor.spawnProcess(
    proto,
    b"find",
    [
        b"find", b"/var/log",
        b"-type", b"f",
        b"-name", b"*.log",
        b"-newermt", b"2018-01-01 00:00:00",
        b"!", b"-newermt", b"2018-02-06 23:59:59",
        b"-exec", b"cat", b"{}", b"+",
    ],
    env=environ,
)
reactor.callLater(.5, find.signalProcess, b"KILL")
reactor.run()

【讨论】:

  • 感谢 Jean,我开始慢慢了解这一切是如何运作的。我仍然无法实现我试图做的事情。我已经编写了我的应用程序正在尝试做的事情的简化版本。我已经阅读了更多扭曲的文档,但仍然遇到了障碍。我觉得很亲近……
猜你喜欢
  • 1970-01-01
  • 2011-12-11
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 2020-04-23
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
相关资源
最近更新 更多