【问题标题】:Can I use fdpexpect on a file that's currently being written to?我可以在当前正在写入的文件上使用 fdpexpect 吗?
【发布时间】:2014-09-11 01:16:29
【问题描述】:

我正在尝试等到一些文本被写入 Python 中的实时日志文件。

fdpexect 似乎是正确的选择,但它并没有等待。一旦到达文件末尾,它就会终止。

我想知道 fdpexpect 是否不支持这个,我需要解决它吗?

我的代码基本上是这样的:

创建生成对象:

# we're not using pexpect.spawn because we want
# all the output to be written to the logfile in real time, 
# which spawn doesn't seem to support.

p = subprocess.Popen(command,
                     shell=shell,
                     stdout=spawnedLog.getFileObj(),
                     stderr=subprocess.STDOUT)
# give fdspawn the same file object we gave Popen
return (p, pexpect.fdpexpect.fdspawn(spawnedLog.getFileObj()))

等待某事:

pexpectObj.expect('something')

这基本上会在 'something' 事件发生并出现 EOF 错误之前立即退出。

【问题讨论】:

  • 好吧,documentation of fdpexpect 是这样说的:“这允许您将 Pexpect 与套接字和命名管道 (FIFO) 一起使用。” 我假设没有“文件” " 从该列表中表示它不受支持。
  • 当然可以,但是前面的那一行说“但是它可以与您传递的任何文件描述符一起使用。”
  • 是的,但我认为问题在于套接字和命名管道在连接关闭之前不会发送 EOF。普通文件将在您读取整个文件后立即发送 EOF - 没有任何机制可以使 pexpect 不断检查文件是否有新内容写入。
  • 好的。除了“产生一个'tail -f '进程并期待它”之外,还有什么想法?
  • 你能不能用tee写到stdout 日志文件,例如pexpect.spawn("command | tee log.log")?

标签: python python-2.7 pexpect


【解决方案1】:

fdpexpect 不是为处理普通文件而设计的。 pexpect 将始终从文件对象读取,直到它到达 EOF - 对于管道和套接字,这在连接实际关闭之前不会发生,但对于普通文件,它会在整个文件被读取后立即发生。它无法知道该文件是否正在被另一个进程写入。

您可以通过使用os.pipe 创建一个管道来解决此问题,然后实现您自己的tee 功能,以将您的进程的stdout 写入该管道以及日志文件。这是一个似乎可行的小玩具示例:

from subprocess import Popen, PIPE, STDOUT
from threading  import Thread
import os
import pexpect.fdpexpect

# tee and teed_call are based on http://stackoverflow.com/a/4985080/2073595

def tee(infile, *files):
    """Print `infile` to `files` in a separate thread."""
    def fanout(infile, *files):
        for line in iter(infile.readline, ''):
            for f in files:
                f.write(line)
        infile.close()
    t = Thread(target=fanout, args=(infile,)+files)
    t.daemon = True
    t.start()
    return t

def teed_call(cmd_args, files, **kwargs):
    p = Popen(cmd_args,
              stdout=PIPE,
              stderr=STDOUT,
              **kwargs)
    threads = []
    threads.append(tee(p.stdout, *files))
    return (threads, p)

with open("log.txt", 'w') as logf:
    # Create pipes for unbuffered reading and writing
    rpipe, wpipe = os.pipe()
    rpipe = os.fdopen(rpipe, 'r', 0)
    wpipe = os.fdopen(wpipe, 'w', 0)

    # Have pexpect read from the readable end of the pipe
    pobj = pexpect.fdpexpect.fdspawn(rpipe)

    # Call some script, and tee output to our log file and
    # the writable end of the pipe.
    threads, p = teed_call(["./myscript.sh"], [wpipe, logf])

    # myscript.sh will print 'hey'
    pobj.expect("hey")

    # orderly shutdown/cleanup
    for t in threads: t.join()
    p.wait()
    rpipe.close()
    wpipe.close()

【讨论】:

    【解决方案2】:

    dano 的另一种方法是硬着头皮使用“tail -f”。

    这有点做作,取决于你是否有可用的“尾巴”。

    p = subprocess.Popen(command,
                         shell=shell,
                         stdout=spawnedLog.getFileObj(),
                         stderr=subprocess.STDOUT)
    
    # this seems really dumb, but in order to follow the log                                                                                                                                                     
    # file and not have fdpexect quit because we encountered EOF                                                                                                                                                 
    # we're going spawn *another* process to tail the log file                                                                                                                                                   
    tailCommand = "tail -f %s" % spawnedLog.getPath()
    
    # this is readonly, we're going to look at the output logfile                                                                                                                                                
    # that's created                                                                                                                                                                                             
    return (p, pexpect.spawn(tailCommand))
    

    【讨论】:

      猜你喜欢
      • 2015-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-09
      • 1970-01-01
      • 1970-01-01
      • 2011-08-15
      • 2020-06-18
      相关资源
      最近更新 更多