web-dev-qa-db-ja.com

テール-Fに相当するPythonicを実装する方法は?

特定のキーワードの出現について、成長するファイルの末尾を監視するPythonの方法は何ですか?

シェルで私は言うかもしれません:

tail -f "$file" | grep "$string" | while read hit; do
    #stuff
done
25
pra

さて、最も簡単な方法は、ファイルから絶えず読み取り、新機能を確認し、ヒットをテストすることです。

import time

def watch(fn, words):
    fp = open(fn, 'r')
    while True:
        new = fp.readline()
        # Once all lines are read this just returns ''
        # until the file changes and a new line appears

        if new:
            for Word in words:
                if Word in new:
                    yield (Word, new)
        else:
            time.sleep(0.5)

fn = 'test.py'
words = ['Word']
for hit_Word, hit_sentence in watch(fn, words):
    print "Found %r in line: %r" % (hit_Word, hit_sentence)

readlineを使用したこのソリューションは、データが行に表示されることがわかっている場合に機能します。

データがある種のストリームである場合は、探している最大のWordよりも大きいバッファーが必要であり、最初にそれを埋めます。そうすると少し複雑になります...

24
Jochen Ritzel
def tail(f):
    f.seek(0, 2)

    while True:
        line = f.readline()

        if not line:
            time.sleep(0.1)
            continue

        yield line

def process_matches(matchtext):
    while True:
        line = (yield)  
        if matchtext in line:
            do_something_useful() # email alert, etc.


list_of_matches = ['ERROR', 'CRITICAL']
matches = [process_matches(string_match) for string_match in list_of_matches]    

for m in matches: # prime matches
    m.next()

while True:
    auditlog = tail( open(log_file_to_monitor) )
    for line in auditlog:
        for m in matches:
            m.send(line)

これを使用してログファイルを監視します。完全な実装では、list_of_matchesを構成ファイルに保持して、複数の目的に使用できるようにします。私の拡張機能のリストには、単純な「in」一致ではなく正規表現のサポートがあります。

6
user166278

Selectを使用して、ファイル内の新しいコンテンツをポーリングできます。

def tail(filename, bufsize = 1024):
    fds = [ os.open(filename, os.O_RDONLY) ]
    while True:
        reads, _, _ = select.select(fds, [], [])
        if 0 < len(reads):
            yield os.read(reads[0], bufsize)
4
Corey Porter

使用できます pytailf :シンプルpython tail-fラッパー

from tailf import tailf    

for line in tailf("myfile.log"):
    print line
3
kommradHomer

編集:以下のコメントにあるように、O_NONBLOCKはディスク上のファイルでは機能しません。これは、他の誰かがソケットや名前付きパイプ、または別のプロセスからのデータのテールを探しに来た場合でも役立ちますが、尋ねられた実際の質問には答えません。元の答えは後世のために以下に残ります。 (tailとgrepへの呼び出しは機能しますが、とにかく一種の答えではありません。)

O_NONBLOCKでファイルを開き、selectを使用して読み取りの可用性をポーリングしてから、readを使用して新しいデータを読み取り、文字列メソッドを使用してファイルの最後の行をフィルタリングします...またはsubprocessモジュールを使用してtailgrepは、シェルの場合と同じように作業を行います。

3
Walter Mundt

そのためのパッケージがあるようです: https://github.com/kasun/python-tail

2
tobych

行ベースの読み取りで機能するように問題を制約できない場合は、ブロックに頼る必要があります。

これは機能するはずです:

import sys

needle = "needle"

blocks = []

inf = sys.stdin

if len(sys.argv) == 2:
    inf = open(sys.argv[1])

while True:
    block = inf.read()
    blocks.append(block)
    if len(blocks) >= 2:
        data = "".join((blocks[-2], blocks[-1]))
    else:
        data = blocks[-1]

    # attention, this needs to be changed if you are interested
    # in *all* matches separately, not if there was any match ata all
    if needle in data:
        print "found"
        blocks = []
    blocks[:-2] = []

    if block == "":
        break

課題は、2つのブロック境界で区切られている場合でも、針を確実に一致させることにあります。

1
deets

書かれているテキストファイルの行を処理するための非常に単純なPython 3ソリューションが必要であり、Windowsサポートが必要ない場合、これは私にとってうまく機能しました:

import subprocess
def tailf(filename):
    #returns lines from a file, starting from the beginning
    command = "tail -n +1 -F " + filename
    p = subprocess.Popen(command.split(), stdout=subprocess.PIPE, universal_newlines=True)
    for line in p.stdout:
        yield line
for line in tailf("logfile"):
    #do stuff

新しい行が書き込まれるのを待つのをブロックするため、これはいくつかの変更を加えずに非同期で使用するのには適していません。

0
James

私の知る限り、Python関数リストには「tail」に相当するものはありません。解決策は、tell()(ファイルサイズを取得)とread()を使用して終了行を計算することです。

このブログ投稿(私ではない)には関数が書き出されており、私には適切に見えます! http://www.manugarg.com/2007/04/real-tailing-in-python.html

0
Zoe Adams