Python和Pytest调用包含tail的shell命令失败

Python和Pytest调用包含tail的shell命令失败,python,pytest,qnx,Python,Pytest,Qnx,环境: 平台qnx——Python 2.7.12、pytest-4.6.9、py-1.8.1、Plugy-0.13.1 插件:json-report-1.2.1、shell-0.2.3 注: 我知道Python2.7很旧,不受支持,但目前QNX没有其他版本 问题: 我正在运行一个测试,当某个关键字出现在某个服务的日志中时,该测试应该会终止该服务。为此,我需要在后台运行它。 为此,我使用以下shell命令: def test_kill_process(): expected_output=

环境: 平台qnx——Python 2.7.12、pytest-4.6.9、py-1.8.1、Plugy-0.13.1 插件:json-report-1.2.1、shell-0.2.3

注: 我知道Python2.7很旧,不受支持,但目前QNX没有其他版本

问题:

我正在运行一个测试,当某个关键字出现在某个服务的日志中时,该测试应该会终止该服务。为此,我需要在后台运行它。 为此,我使用以下shell命令:

def test_kill_process():
    expected_output="XXXXXXXXX"
    expected_rc=0
    check_kill_process(expected_output, expected_rc)

import os
def check_kill_process(expected_output, expected_rc):
    test_log = File(r"/path/to/log")
    erase_log_entry = "Action"
    service=MyService()
    service.start()
    sleep(2)
    kill_command = "tail -f " + test_log.file_path + " | grep --line-buffered " + erase_log_entry + \
            " | while read ; do kill " + service.pid + " ; done &"
    os.popen(kill_command)
    service.action()
    f = open(test_log.file_path, "r")
    output = f.read()
    assert re.search(expected_output, output)
========================================================================

没有Pytest甚至Python,它的工作就像一个符咒

如果我尝试使用subprocess模块运行该命令,测试将无限期冻结。 如果我尝试使用os.popen或os.system,命令将以错误结尾:

tail:  read failed in '/path/to/logfile' (Invalid argument)
此外,如果我试着做同样的事情,只要一只“猫”,我就会得到这样的结果:

--stdout--: Broken pipe

如果有人有任何想法,请提前感谢

与其使用
子流程
(这通常是unidiomatic python的症状),不如只
打开(日志文件,'r')
,并在循环中使用
file.readline()
来读取文件?这将产生与使用
tail
相同的效果,而不需要子流程的开销(生成的代码也更干净、更容易理解)

这对于您要做的事情应该非常有效:

def wait_for_line(filename):
    f = open(filename, 'r')
    while 1:
        if line := f.readline():
            if re.match(some_regex, line):
                return True
        else:
            sleep(0.5)
下面是一个完整的工作示例:

import threading
from time import sleep
import re

FILENAME = 'some_file'
REGEX = r'^foo\s...!\s\d+$'
REGEX_MATCH = "foo bar! 123"

def perform_other_action(filename):
    f = open(filename, 'w')
    sleep(5) # just for effect
    f.write(REGEX_MATCH)


def wait_for_line(filename):
    f = open(filename, 'r')
    while 1:
        if line := f.readline():
            if re.match(REGEX, line):
                return True
        else:
            sleep(0.5) # throttle the read frequency if no new lines are found

with open(FILENAME, 'w') as f: # make sure file exists
    pass

t = threading.Thread(target=wait_for_line, args=(FILENAME,))
t.start() # returns immediately, wait_for_line runs in background
perform_other_action(FILENAME)
t.join()

根据经验,subprocess和popen喜欢命令序列而不是字符串。我认为技术原因在于不同的系统如何解释字符串路径和参数。有关部门内的更多说明,请查看

但是,例如,如果我想执行命令
git commit-m“修复一个bug”。
我必须将该字符串命令拆分为一个由空格分隔的列表

#命令作为字符串
cmd='git commit-m“修复了一个bug。”
#命令作为参数序列。考虑使用SLEX.SPLIT()代替
cmd=cmd.split(“”)
#现在使用新的格式化参数调用popen
os.popen(cmd)
使脚本更加健壮。对于更复杂的情况,可以使用内置函数
shlex.split()
将字符串拆分为类似shell的语法


另外,看起来您还在命令中使用
|
管道。调用popen使管道工作时,必须传递
shell=True

如果尝试使用子流程-
subprocess
在空环境中运行,则不会定义
日志文件
关键字
。使用
env
arg传递环境。对不起,我在这里写得不太好。我直接传递参数,而不是作为shell变量。我重写了这个问题。感谢您的及时回答,但这不是问题…请共享完整的源代码问题是我需要在后台运行此代码,以便我还可以向服务发出最终将与shell行中的条件匹配的操作。@RazvanBadea在启动此循环之前,您能运行该操作吗?如果不可能,那么创建第二个线程来管理操作如何?我的第一个选择是线程。我遇到了同样的问题-挂起。我甚至制作了一个小的testscript,它单独使用python运行得很好,但使用PyTest挂起。不过我会尝试颠倒顺序。您是否尝试过用本机
os.kill()
方法替换子流程?将
MyService()
设置放在测试夹具中也是一个好主意。谢谢您的输入。始终使用子流程的列表,但不知道shlex。但这仍然不能解决我的问题。对于subprocess.Popen(shlex.split(kill_命令)),它只是挂起。看起来您还在命令中使用
|
管道。调用popen使管道工作时,必须传递
shell=True
。根据这篇文章尝试过,但结果相同。测试无限期地挂起。