Non Blocking

If you are on linux (as windows does not support calling select on files) you can use the subprocess module along with the select module.

import time
import subprocess
import select

f = subprocess.Popen(['tail','-F',filename],\
        stdout=subprocess.PIPE,stderr=subprocess.PIPE)
p = select.poll()
p.register(f.stdout)

while True:
    if p.poll(1):
        print f.stdout.readline()
    time.sleep(1)

This polls the output pipe for new data and prints it when it is available. Normally the time.sleep(1) and print f.stdout.readline() would be replaced with useful code.

Blocking

You can use the subprocess module without the extra select module calls.

import subprocess
f = subprocess.Popen(['tail','-F',filename],\
        stdout=subprocess.PIPE,stderr=subprocess.PIPE)
while True:
    line = f.stdout.readline()
    print line

This will also print new lines as they are added, but it will block until the tail program is closed, probably with f.kill().

Answer from Matt on Stack Overflow
🌐
W3Schools
w3schools.com › python › pandas › ref_df_tail.asp
Pandas DataFrame tail() Method
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.
Top answer
1 of 14
83

Non Blocking

If you are on linux (as windows does not support calling select on files) you can use the subprocess module along with the select module.

import time
import subprocess
import select

f = subprocess.Popen(['tail','-F',filename],\
        stdout=subprocess.PIPE,stderr=subprocess.PIPE)
p = select.poll()
p.register(f.stdout)

while True:
    if p.poll(1):
        print f.stdout.readline()
    time.sleep(1)

This polls the output pipe for new data and prints it when it is available. Normally the time.sleep(1) and print f.stdout.readline() would be replaced with useful code.

Blocking

You can use the subprocess module without the extra select module calls.

import subprocess
f = subprocess.Popen(['tail','-F',filename],\
        stdout=subprocess.PIPE,stderr=subprocess.PIPE)
while True:
    line = f.stdout.readline()
    print line

This will also print new lines as they are added, but it will block until the tail program is closed, probably with f.kill().

2 of 14
57

Using the sh module (pip install sh):

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

[update]

Since sh.tail with _iter=True is a generator, you can:

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

Then you can "getNewData" with:

new_data = tail.next()

Note that if the tail buffer is empty, it will block until there is more data (from your question it is not clear what you want to do in this case).

[update]

This works if you replace -f with -F, but in Python it would be locking. I'd be more interested in having a function I could call to get new data when I want it, if that's possible. – Eli

A container generator placing the tail call inside a while True loop and catching eventual I/O exceptions will have almost the same effect of -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

If the file becomes inaccessible, the generator will return None. However it still blocks until there is new data if the file is accessible. It remains unclear for me what you want to do in this case.

Raymond Hettinger approach seems pretty good:

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 ''

This generator will return '' if the file becomes inaccessible or if there is no new data.

[update]

The second to last answer circles around to the top of the file it seems whenever it runs out of data. – Eli

I think the second will output the last ten lines whenever the tail process ends, which with -f is whenever there is an I/O error. The tail --follow --retry behavior is not far from this for most cases I can think of in unix-like environments.

Perhaps if you update your question to explain what is your real goal (the reason why you want to mimic tail --retry), you will get a better answer.

The last answer does not actually follow the tail and merely reads what's available at run time. – Eli

Of course, tail will display the last 10 lines by default... You can position the file pointer at the end of the file using file.seek, I will left a proper implementation as an exercise to the reader.

IMHO the file.read() approach is far more elegant than a subprocess based solution.

🌐
GitHub
gist.github.com › amitsaha › 5990310
Simple implementation of the tail command in Python · GitHub
And yet another way of doing this: tailhead and pytailer. ... For what it's worth, I adapted some code from here, basically just using seek() and read() one at time to read backwards and count newlines, that way you don't need a buffer. #!/usr/bin/python3 import os,sys def tail_file(filename, nlines): with open(filename) as qfile: qfile.seek(0, os.SEEK_END) endf = position = qfile.tell() linecnt = 0 while position >= 0: qfile.seek(position) next_char = qfile.read(1) if next_char == "\n" and position != endf-1: linecnt += 1 if linecnt == nlines: break position -= 1 if position < 0: qfile.seek(0) print(qfile.read(),end='') if __name__ == '__main__': filename = sys.argv[1] nlines = int(sys.argv[2]) tail_file(filename, nlines)
🌐
W3Schools
w3schools.com › python › pandas › pandas_analyzing.asp
Pandas - Analyzing DataFrames
The tail() method returns the headers and a specified number of rows, starting from the bottom. ... The DataFrames object has a method called info(), that gives you more information about the data set.
🌐
Lethain
lethain.com › tailing-in-python
Tailing in Python | Irrational Exuberance
May 16, 2010 - A quick and pointless look at implementing tail in Python. Something of a koan.
🌐
Reddit
reddit.com › r/learnpython › tail -f equivalent in python?
r/learnpython on Reddit: tail -f equivalent in python?
January 10, 2014 -

I have a text file that's being written to constantly and I need to use the data that's being added to the end of the file in real time.

On *nix systems, I use tail -f for log files that works well.. but say I want to do this within python, what's the best method of doing this?

Files will be read only by python, and open / actively being written to by another process as python reads.

(and no, I can't hook into the other process directly, I must read a txt file in real time...)

Ideally I'd like to avoid doing a 'read' on the file every few milliseconds to detect new lines... hence looking for something like tail...

thanks!

EDIT: PS. I did google this before, but I found solutions that were OS specific.. I'm hoping there's some library or built in feature that is platform agnostic so I can port this script.

🌐
The Code Library
ayada.dev › posts › implement-tail-command-in-python
The Code Library | Implement tail command in Python
January 12, 2021 - import argparse import queue def tail(filename, n): q = queue.Queue() size = 0 with open(filename) as fh: for line in fh: q.put(line.strip()) if size >= n: q.get() else: size += 1 for i in range(size): print(q.get()) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Print last n lines from a file.') parser.add_argument('file', type=str, help='File to read from') parser.add_argument('-n', type=int, default=10, help='The last n lines to be printed') args = parser.parse_args() tail(args.file, args.n)
Find elsewhere
🌐
GitHub
github.com › kasun › python-tail
GitHub - kasun/python-tail: Unix tail follow implementation in python · GitHub
python setup.py install · import tail # Create a tail instance t = tail.Tail('file-to-be-followed') # Register a callback function to be called when a new line is found in the followed file. # If no callback function is registerd, new lines would be printed to standard out.
Starred by 297 users
Forked by 107 users
Languages   Python
🌐
Plantsandpython
plantsandpython.github.io › PlantsAndPython › G_4_DATA_ANALYSIS_WITH_PANDAS › 0_Lessons › 4.1_Head_and_Tail.html
4.1 Head and Tail — Plants & Python
We can also use tail. And tail, if the head is at the beginning, then the tail is the end. You can see that we get the last rows in our dataset. Tail is very useful to see just how many rows that you have overall.
🌐
PyPI
pypi.org › project › tailer
tailer
JavaScript is disabled in your browser. Please enable JavaScript to proceed · A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, or try using a different browser
🌐
w3resource
w3resource.com › pandas › dataframe › dataframe-tail.php
Pandas DataFrame: tail() function - w3resource
August 19, 2022 - ▼Python Pandas Tutorials · Pandas Home · ▼Pandas DataFrame Constructor · Pandas DataFrame Home · ▼Pandas DataFrame Attributes · ▼DataFrame Indexing, iteration · DataFrame.head() DataFrame.at() DataFrame.iat() DataFrame.loc() DataFrame.iloc() DataFrame.items() DataFrame.iteritems() DataFrame.iterrows() DataFrame.itertuples() DataFrame.lookup() DataFrame.pop() DataFrame.tail() DataFrame.xs() DataFrame.isin() DataFrame.where() DataFrame.mask() DataFrame.query() ..More to come..
🌐
TutorialsPoint
tutorialspoint.com › article › python-pandas-how-to-use-pandas-dataframe-tail-function
Python Pandas – How to use Pandas DataFrame tail( ) function
May 27, 2024 - import pandas as pd # Create sample data data = { 'id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'product': ['Laptop', 'Phone', 'Tablet', 'Watch', 'Camera', 'Speaker', 'Headset', 'Monitor', 'Keyboard', 'Mouse'], 'price': [45000, 25000, 35000, 15000, 55000, 8000, 12000, 42000, 3000, 2500] } df = pd.DataFrame(data) # Filter products with price between 30000 to 70000 filtered_df = df[(df['price'] >= 30000) & (df['price'] <= 70000)] print("Filtered products (price 30000-70000):") print(filtered_df) # Get last 3 rows with specific columns result = filtered_df[['id', 'product']].tail(3) print("\nLast 3 rows (id and product columns):") print(result)
🌐
Pandas
pandas.pydata.org › docs › reference › api › pandas.DataFrame.tail.html
pandas.DataFrame.tail — pandas 3.0.2 documentation
Return the last n rows · This function returns last n rows from the object based on position. It is useful for quickly verifying data, for example, after sorting or appending rows
🌐
W3Schools
w3schools.com › bash › bash_tail.php
Bash tail Command - Display Last Part of Files
The tail command is used to display the last part of files. It's particularly useful for viewing the end of log files or any file that is being updated in real-time.
🌐
DEV Community
dev.to › abvarun226 › implement-tail-command-in-python-4nn8
Implement tail command in Python - DEV Community
January 4, 2022 - import argparse import queue def tail(filename, n): q = queue.Queue() size = 0 with open(filename) as fh: for line in fh: q.put(line.strip()) if size >= n: q.get() else: size += 1 for i in range(size): print(q.get()) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Print last n lines from a file.') parser.add_argument('file', type=str, help='File to read from') parser.add_argument('-n', type=int, default=10, help='The last n lines to be printed') args = parser.parse_args() tail(args.file, args.n)
🌐
ActiveState
code.activestate.com › recipes › 157035-tail-f-in-python
tail -f in Python « Python recipes « ActiveState Code
October 16, 2002 - import sys def tail_lines(filename,linesback=10,returnlist=0): """Does what "tail -10 filename" would have done Parameters: filename file to read linesback Number of lines to read from end of file returnlist Return a list containing the lines instead of a string """ avgcharsperline=75 file = open(filename,'r') while 1: try: file.seek(-1 * avgcharsperline * linesback,2) except IOError: file.seek(0) if file.tell() == 0: atstart=1 else: atstart=0 lines=file.read().split("\n") if (len(lines) > (linesback+1)) or atstart: break #The lines are bigger than we thought avgcharsperline=avgcharsperline *
🌐
GeeksforGeeks
geeksforgeeks.org › dsa › tail-recursion-in-python
Tail Recursion in Python - GeeksforGeeks
July 23, 2025 - This allows certain optimizations, known as tail call optimization (TCO), where the compiler or interpreter can reuse the current function's stack frame for the recursive call, effectively converting the recursion into iteration and preventing stack overflow errors. However, it's important to note that Python does not natively support tail call optimization.
🌐
Medium
medium.com › @aliasav › how-follow-a-file-in-python-tail-f-in-python-bca026a901cf
How to follow a file in Python (tail -f in Python) | by Saurabh AV | Medium
March 20, 2020 - How to follow a file in Python (tail -f in Python) In this blog post, we see how we can create a simple version of tail -f file in Python. What are we doing? We want to read a file using Python and …
🌐
Codecademy
codecademy.com › docs › python:pandas › dataframe › .tail()
Python:Pandas | DataFrame | .tail() | Codecademy
July 8, 2024 - In Pandas, .tail() is a method that returns the last n rows of a DataFrame. By default, it returns the last 5 rows, but the number of rows can be adjusted by passing an integer argument to the method.
🌐
PyPI
pypi.org › project › pythontail
pythontail · PyPI
item: multiple files support description: tail as many files as wanted with all available parameters working as well status: [OK] item: usage as both terminal command and as python module description: the use of all parameters within terminal command line and by importing as a module inside a python script status: [OK]
      » pip install pythontail
    
Published   Feb 21, 2024
Version   0.9