Hướng dẫn python tail file - tệp đuôi trăn

Sử dụng mô -đun SH (Cài đặt PIP SH):

from sh import tail
# runs forever
for line in tail("-f", "/var/log/some_log_file.log", _iter=True):
    print(line)

[update]

Vì sh.tail với ________ 6 = true là một trình tạo, bạn có thể:

import sh
tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)

Sau đó, bạn có thể "getnewdata" với:

new_data = tail.next()

Lưu ý rằng nếu bộ đệm đuôi trống, nó sẽ chặn cho đến khi có nhiều dữ liệu hơn (từ câu hỏi của bạn, không rõ bạn muốn làm gì trong trường hợp này).

[update]

Điều này hoạt động nếu bạn thay thế -f bằng -f, nhưng trong Python, nó sẽ bị khóa. Tôi quan tâm nhiều hơn đến việc có một chức năng mà tôi có thể gọi để có được dữ liệu mới khi tôi muốn, nếu điều đó có thể. - Eli

Một trình tạo container đặt cuộc gọi đuôi bên trong một vòng lặp thực sự và bắt gặp các ngoại lệ I/O cuối cùng sẽ có hiệu ứng gần như tương tự của -F.

def tail_F(some_file):
    while True:
        try:
            for line in sh.tail("-f", some_file, _iter=True):
                yield line
        except sh.ErrorReturnCode_1:
            yield None

Nếu tệp không thể truy cập, trình tạo sẽ trả về không. Tuy nhiên, nó vẫn chặn cho đến khi có dữ liệu mới nếu tệp có thể truy cập được. Vẫn chưa rõ đối với tôi những gì bạn muốn làm trong trường hợp này.

Cách tiếp cận Raymond Hettinger có vẻ khá tốt:

def tail_F(some_file):
    first_call = True
    while True:
        try:
            with open(some_file) as input:
                if first_call:
                    input.seek(0, 2)
                    first_call = False
                latest_data = input.read()
                while True:
                    if '\n' not in latest_data:
                        latest_data += input.read()
                        if '\n' not in latest_data:
                            yield ''
                            if not os.path.isfile(some_file):
                                break
                            continue
                    latest_lines = latest_data.split('\n')
                    if latest_data[-1] != '\n':
                        latest_data = latest_lines[-1]
                    else:
                        latest_data = input.read()
                    for line in latest_lines[:-1]:
                        yield line + '\n'
        except IOError:
            yield ''

Trình tạo này sẽ trả về '' nếu tệp không thể truy cập hoặc nếu không có dữ liệu mới.

[update]

Câu trả lời thứ hai đến cuối cùng xung quanh đến đầu tệp có vẻ như bất cứ khi nào nó hết dữ liệu. - Eli

Tôi nghĩ rằng thứ hai sẽ xuất ra mười dòng cuối cùng bất cứ khi nào quá trình đuôi kết thúc, mà với -f là bất cứ khi nào có lỗi I/O. Hành vi tail --follow --retry không xa điều này đối với hầu hết các trường hợp tôi có thể nghĩ đến trong các môi trường giống UNIX.

Có lẽ nếu bạn cập nhật câu hỏi của mình để giải thích mục tiêu thực sự của bạn là gì (lý do tại sao bạn muốn bắt chước đuôi -retry), bạn sẽ nhận được câu trả lời tốt hơn.

Câu trả lời cuối cùng không thực sự theo đuôi và chỉ đọc những gì có sẵn trong thời gian chạy. - Eli

Tất nhiên, Tail sẽ hiển thị 10 dòng cuối cùng theo mặc định ... bạn có thể định vị con trỏ tệp ở cuối tệp bằng tệp.Seek, tôi sẽ để lại một triển khai thích hợp như một bài tập cho người đọc.

IMHO Phương pháp tiếp cận tệp.read () thanh lịch hơn nhiều so với một giải pháp dựa trên quy trình con.

Trong bài đăng trên blog này, chúng tôi thấy cách chúng tôi có thể tạo một phiên bản đơn giản của tail -f file trong Python.

Chúng ta đang làm gì?

Chúng tôi muốn đọc một tệp bằng Python và tiếp tục đọc tệp, vô hạn. Chúng tôi muốn theo dõi một tập tin. Về cơ bản, chúng tôi muốn mô phỏng lệnh Unix ____ không có:

`đuôi -f` là một lệnh được sử dụng rộng rãi khi giám sát nhật ký máy chủ

Chúng tôi đang đọc một luồng dữ liệu vô hạn của người Viking. Dưới đây là một vài điều cần ghi nhớ:

  • Chúng tôi muốn liên tục xem tệp và các dòng mang lại ngay khi các dòng mới được ghi vào tệp
  • Nhưng chúng tôi không thực sự biết bao nhiêu dữ liệu sẽ thực sự được viết
  • Các tệp nhật ký thường có thể rất lớn (vì vậy không có câu hỏi về việc đọc toàn bộ tệp mỗi lần và tìm kiếm các bản cập nhật)

Làm sao chúng ta làm điều này?

Chúng tôi sẽ viết một kịch bản Python đơn giản và sử dụng các khái niệm pythonic như

import sh
tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)
1.

Tuyên bố miễn trừ trách nhiệm: Trong một kịch bản sản xuất trong thế giới thực, nó có lẽ là một ý tưởng xấu (không thể mở rộng) bằng cách sử dụng Python để tạo ra một cái gì đó như thế này, chúng tôi đã làm điều này chỉ để giải trí.

Hãy để xem một số mã

import time
import os
def follow(thefile):
'''generator function that yields new lines in a file
'''
# seek the end of the file
thefile.seek(0, os.SEEK_END)

# start infinite loop
while True:
# read last line of file
line = thefile.readline()

# sleep if file hasn't been updated
if not line:
time.sleep(0.1)
continue

yield line


if __name__ == '__main__':

logfile = open("run/foo/access-log","r")
loglines = follow(logfile)

# iterate over the generator
for line in loglines:
print(line)

Những gì xảy ra ở đây:

  • Chúng tôi tạo hàm
    import sh
    tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)
    
    2 chấp nhận tệp và
    import sh
    tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)
    
    3 (và không trả về) một chuỗi các dòng
  • Chúng tôi lặp lại trên trình tạo và tiếp tục in các dòng mới được ghi vào tệp
  • Một vòng lặp vô hạn được sinh ra trong hàm máy phát
    import sh
    tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)
    
    2 tạo ra

Một chút trên máy phát điện

Ở đây,

import sh
tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)
2 là một loại chức năng đặc biệt gọi là trình tạo. Điều gì xảy ra dưới mui xe:generator. What happens under the hood:

  • Khi một trình tạo gặp phải `loglines = theo dõi (logfile)`: thực thi chức năng được tạm dừng và một đối tượng máy phát được trả về (điều này chứa các biến trạng thái liên quan đến hàm)
  • chức năng thực tế chạy khi chúng tôi lặp lại đối tượng máy phát đã được trả về trước đó
  • Vì vậy, khi chúng tôi lặp lại một phương thức
    import sh
    tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)
    
    6 được thực thi, đó là khi hàm trình tạo thực thi và giá trị là
    import sh
    tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True)
    
    7

Tóm lại: Trình tạo là các hàm trả về các đối tượng, có thể được lặp lại, thường được tiêu thụ trong các vòng lặp.

Sự kết luận

Các luồng vô hạn là khó khăn, máy phát điện rất vui và Python rất tiện dụng!

Đây là một số tài nguyên tuyệt vời trên máy phát điện:

  • https://realpython.com/introduction-to-python-generators
  • http://www.dabeaz.com/generators/Generators.pdf
  • https://wiki.python.org/moin/Generators