python - ¿Cómo implementar un equivalente pitónico de cola-F?
file tail (10)
Bueno, la forma más simple sería leer constantemente del archivo, verificar las novedades y probar los hits.
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)
Esta solución con readline
funciona si sabes que tus datos aparecerán en líneas.
Si los datos son algún tipo de flujo, necesitas un buffer, más grande que la word
más grande que estás buscando, y llenarlo primero. Se pone un poco más complicado de esa manera ...
¿Cuál es la forma pitónica de ver el final de un archivo en crecimiento para la aparición de ciertas palabras clave?
En shell, podría decir:
tail -f "$file" | grep "$string" | while read hit; do
#stuff
done
EDITAR: como indica el comentario a continuación, O_NONBLOCK
no funciona para archivos en disco. Esto todavía ayudará si alguien más busca datos de la cola procedentes de un socket o tubería con nombre u otro proceso, pero no responde la pregunta real que se le hizo . La respuesta original permanece debajo para la posteridad. (Llamar a tail y grep funcionará, pero de todos modos no responde).
O_NONBLOCK
el archivo con O_NONBLOCK
y use select
para buscar disponibilidad de lectura y luego read
para leer los nuevos datos y los métodos de cadena para filtrar las líneas al final de un archivo ... o simplemente use el módulo de subprocess
y deje que tail
y grep
hagan el trabajo para ti tal como lo harías en el caparazón.
Parece que hay un paquete para eso: https://github.com/kasun/python-tail
Puede usar collections.deque
para implementar tail.
Desde http://docs.python.org/library/collections.html#deque-recipes ...
def tail(filename, n=10):
''Return the last n lines of a file''
return deque(open(filename), n)
Por supuesto, esto lee el contenido completo del archivo, pero es una forma ordenada y concisa de implementar la cola.
Puede utilizar seleccionar para sondear los nuevos contenidos en un archivo.
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)
Que yo sepa, no hay equivalente a "cola" en la lista de funciones de Python. La solución sería usar tell () (obtener tamaño de archivo) y read () para calcular las líneas finales.
¡Esta publicación del blog (no por mí) tiene la función escrita, parece apropiada para mí! http://www.manugarg.com/2007/04/real-tailing-in-python.html
Si no puede restringir el problema de que funcione para una lectura basada en línea, necesita recurrir a bloques.
Esto debería funcionar:
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
El desafío radica en garantizar que coincida con la aguja, incluso si está separada por dos límites de bloques.
Si solo necesitas una solución de Python 3 muerta y simple para procesar las líneas de un archivo de texto a medida que están escritas, y no necesitas el soporte de Windows, esto funcionó bien para mí:
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
Bloquea la espera de que se escriban nuevas líneas, por lo que no es adecuado para uso asincrónico sin algunas modificaciones.
puedes usar pytailf : envoltorio de cola de python simple
from tailf import tailf
for line in tailf("myfile.log"):
print line
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)
Yo uso esto para monitorear archivos de registro. En la implementación completa, guardo list_of_matches en un archivo de configuración para que pueda usarse con múltiples propósitos. En mi lista de mejoras es compatible con expresiones regulares en lugar de una simple coincidencia ''in''.