문제

웹 응용 프로그램을 위해 로그 파일 뷰어를 작성하고 로그 파일의 줄을 통해 페이지를 찍고 싶습니다. 파일의 항목은 하단의 최신 항목을 기반으로 한 줄입니다.

그래서 나는 필요하다 tail() 읽을 수있는 방법 n 하단에서 라인과 오프셋을 지원합니다. 내가 생각한 것은 다음과 같이 보입니다.

def tail(f, n, offset=0):
    """Reads a n lines from f with an offset of offset lines."""
    avg_line_length = 74
    to_read = n + offset
    while 1:
        try:
            f.seek(-(avg_line_length * to_read), 2)
        except IOError:
            # woops.  apparently file is smaller than what we want
            # to step back, go to the beginning instead
            f.seek(0)
        pos = f.tell()
        lines = f.read().splitlines()
        if len(lines) >= to_read or pos == 0:
            return lines[-to_read:offset and -offset or None]
        avg_line_length *= 1.3

이것이 합리적인 접근 방식입니까? 오프셋으로 파일을 꼬리 로그 로그를 맞추는 권장 방법은 무엇입니까?

도움이 되었습니까?

해결책 6

내가 사용한 코드. 나는 이것이 지금까지 최고라고 생각합니다.

def tail(f, n, offset=None):
    """Reads a n lines from f with an offset of offset lines.  The return
    value is a tuple in the form ``(lines, has_more)`` where `has_more` is
    an indicator that is `True` if there are more lines in the file.
    """
    avg_line_length = 74
    to_read = n + (offset or 0)

    while 1:
        try:
            f.seek(-(avg_line_length * to_read), 2)
        except IOError:
            # woops.  apparently file is smaller than what we want
            # to step back, go to the beginning instead
            f.seek(0)
        pos = f.tell()
        lines = f.read().splitlines()
        if len(lines) >= to_read or pos == 0:
            return lines[-to_read:offset and -offset or None], \
                   len(lines) > to_read or pos > 0
        avg_line_length *= 1.3

다른 팁

이것은 당신보다 더 빠를 수 있습니다. 라인 길이에 대한 가정이 없습니다. ' n'문자의 올바른 수를 찾을 때까지 파일 한 번에 한 블록 씩 후면.

def tail( f, lines=20 ):
    total_lines_wanted = lines

    BLOCK_SIZE = 1024
    f.seek(0, 2)
    block_end_byte = f.tell()
    lines_to_go = total_lines_wanted
    block_number = -1
    blocks = [] # blocks of size BLOCK_SIZE, in reverse order starting
                # from the end of the file
    while lines_to_go > 0 and block_end_byte > 0:
        if (block_end_byte - BLOCK_SIZE > 0):
            # read the last block we haven't yet read
            f.seek(block_number*BLOCK_SIZE, 2)
            blocks.append(f.read(BLOCK_SIZE))
        else:
            # file too small, start from begining
            f.seek(0,0)
            # only read what was not read
            blocks.append(f.read(block_end_byte))
        lines_found = blocks[-1].count('\n')
        lines_to_go -= lines_found
        block_end_byte -= BLOCK_SIZE
        block_number -= 1
    all_read_text = ''.join(reversed(blocks))
    return '\n'.join(all_read_text.splitlines()[-total_lines_wanted:])

나는 실질적인 문제로 당신이 그런 것을 알 수 없을 때 선 길이에 대한 까다로운 가정을 좋아하지 않습니다.

일반적으로 이것은 루프를 통해 첫 번째 또는 두 번째 패스에서 마지막 20 줄을 찾습니다. 74 캐릭터가 실제로 정확하다면 블록 크기 2048을 만들고 거의 즉시 20 줄을 꼬리게 할 것입니다.

또한, 나는 물리적 OS 블록과 정렬을 정렬하려고 많은 뇌 칼로리를 태우지 않습니다. 이러한 높은 수준의 I/O 패키지를 사용하면 OS 블록 경계에 맞추려고 시도한 성능 결과가 보일 것입니다. 하위 레벨 I/O를 사용하면 속도가 빨라질 수 있습니다.

Python 2의 Unix와 같은 시스템을 가정합니다.

import os
def tail(f, n, offset=0):
  stdin,stdout = os.popen2("tail -n "+n+offset+" "+f)
  stdin.close()
  lines = stdout.readlines(); stdout.close()
  return lines[:,-offset]

Python 3의 경우 다음에 할 수 있습니다.

import subprocess
def tail(f, n, offset=0):
    proc = subprocess.Popen(['tail', '-n', n + offset, f], stdout=subprocess.PIPE)
    lines = proc.stdout.readlines()
    return lines[:, -offset]

전체 파일을 읽을 수있는 경우 Deque를 사용하십시오.

from collections import deque
deque(f, maxlen=n)

2.6 이전에 Deques는 Maxlen 옵션이 없었지만 구현하기에 쉽습니다.

import itertools
def maxque(items, size):
    items = iter(items)
    q = deque(itertools.islice(items, size))
    for item in items:
        del q[0]
        q.append(item)
    return q

끝에서 파일을 읽어야하는 경우 갤럽 (일명 지수) 검색을 사용하십시오.

def tail(f, n):
    assert n >= 0
    pos, lines = n+1, []
    while len(lines) <= n:
        try:
            f.seek(-pos, 2)
        except IOError:
            f.seek(0)
            break
        finally:
            lines = list(f)
        pos *= 2
    return lines[-n:]

여기 내 대답이 있습니다. 순수한 파이썬. Timeit을 사용하면 꽤 빠릅니다. 100,000 줄이있는 로그 파일의 100 줄을 테일링합니다.

>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=10)
0.0014600753784179688
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=100)
0.00899195671081543
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=1000)
0.05842900276184082
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=10000)
0.5394978523254395
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=100000)
5.377126932144165

코드는 다음과 같습니다.

import os


def tail(f, lines=1, _buffer=4098):
    """Tail a file and get X lines from the end"""
    # place holder for the lines found
    lines_found = []

    # block counter will be multiplied by buffer
    # to get the block size from the end
    block_counter = -1

    # loop until we find X lines
    while len(lines_found) < lines:
        try:
            f.seek(block_counter * _buffer, os.SEEK_END)
        except IOError:  # either file is too small, or too many lines requested
            f.seek(0)
            lines_found = f.readlines()
            break

        lines_found = f.readlines()

        # we found enough lines, get out
        # Removed this line because it was redundant the while will catch
        # it, I left it for history
        # if len(lines_found) > lines:
        #    break

        # decrement the block counter to get the
        # next X bytes
        block_counter -= 1

    return lines_found[-lines:]

위의 S.Lott의 대답은 거의 나에게 효과가 있지만 결국 부분 선을 준다. 데이터는 읽기 블록을 역 순서로 유지하기 때문에 블록 경계에 대한 데이터를 손상 시킨다는 것이 밝혀졌습니다. ''.join (데이터)이 호출되면 블록은 잘못된 순서입니다. 이것은 그것을 해결합니다.

def tail(f, window=20):
    """
    Returns the last `window` lines of file `f` as a list.
    f - a byte file-like object
    """
    if window == 0:
        return []
    BUFSIZ = 1024
    f.seek(0, 2)
    bytes = f.tell()
    size = window + 1
    block = -1
    data = []
    while size > 0 and bytes > 0:
        if bytes - BUFSIZ > 0:
            # Seek back one whole BUFSIZ
            f.seek(block * BUFSIZ, 2)
            # read BUFFER
            data.insert(0, f.read(BUFSIZ))
        else:
            # file too small, start from begining
            f.seek(0,0)
            # only read what was not read
            data.insert(0, f.read(bytes))
        linesFound = data[0].count('\n')
        size -= linesFound
        bytes -= BUFSIZ
        block -= 1
    return ''.join(data).splitlines()[-window:]

MMAP를 사용한 간단하고 빠른 솔루션 :

import mmap
import os

def tail(filename, n):
    """Returns last n lines from the filename. No exception handling"""
    size = os.path.getsize(filename)
    with open(filename, "rb") as f:
        # for Windows the mmap parameters are different
        fm = mmap.mmap(f.fileno(), 0, mmap.MAP_SHARED, mmap.PROT_READ)
        try:
            for i in xrange(size - 1, -1, -1):
                if fm[i] == '\n':
                    n -= 1
                    if n == -1:
                        break
            return fm[i + 1 if i else 0:].splitlines()
        finally:
            fm.close()

삽입 및 추가 및 반전되는 더 깨끗한 Python3 호환 버전 :

def tail(f, window=1):
    """
    Returns the last `window` lines of file `f` as a list of bytes.
    """
    if window == 0:
        return b''
    BUFSIZE = 1024
    f.seek(0, 2)
    end = f.tell()
    nlines = window + 1
    data = []
    while nlines > 0 and end > 0:
        i = max(0, end - BUFSIZE)
        nread = min(end, BUFSIZE)

        f.seek(i)
        chunk = f.read(nread)
        data.append(chunk)
        nlines -= chunk.count(b'\n')
        end -= nread
    return b'\n'.join(b''.join(reversed(data)).splitlines()[-window:])

다음과 같이 사용하십시오.

with open(path, 'rb') as f:
    last_lines = tail(f, 3).decode('utf-8')

위의 Popen이 최상의 솔루션이라는 것을 알았습니다. 빠르고 더럽고 유닉스 머신에서 Python 2.6에서 작동합니다. 다음을 사용했습니다.

    def GetLastNLines(self, n, fileName):
    """
    Name:           Get LastNLines
    Description:        Gets last n lines using Unix tail
    Output:         returns last n lines of a file
    Keyword argument:
    n -- number of last lines to return
    filename -- Name of the file you need to tail into
    """
    p=subprocess.Popen(['tail','-n',str(n),self.__fileName], stdout=subprocess.PIPE)
    soutput,sinput=p.communicate()
    return soutput

Soutput은 코드의 마지막 n 줄을 포함합니다. Soutput 라인을 통해 라인별로 반복하기 위해 :

for line in GetLastNLines(50,'myfile.log').split('\n'):
    print line

Python3에 대한 @papercrane 솔루션을 업데이트하십시오. 파일을 엽니 다 open(filename, 'rb') 그리고:

def tail(f, window=20):
    """Returns the last `window` lines of file `f` as a list.
    """
    if window == 0:
        return []

    BUFSIZ = 1024
    f.seek(0, 2)
    remaining_bytes = f.tell()
    size = window + 1
    block = -1
    data = []

    while size > 0 and remaining_bytes > 0:
        if remaining_bytes - BUFSIZ > 0:
            # Seek back one whole BUFSIZ
            f.seek(block * BUFSIZ, 2)
            # read BUFFER
            bunch = f.read(BUFSIZ)
        else:
            # file too small, start from beginning
            f.seek(0, 0)
            # only read what was not read
            bunch = f.read(remaining_bytes)

        bunch = bunch.decode('utf-8')
        data.insert(0, bunch)
        size -= bunch.count('\n')
        remaining_bytes -= BUFSIZ
        block -= 1

    return ''.join(data).splitlines()[-window:]

주석가의 명령에 따라 답변을 게시합니다 비슷한 질문에 대한 나의 대답 동일한 기술이 사용되어 파일의 마지막 줄을 돌연변이하는 것이 아니라 단순히 얻는 것이 아닙니다.

크기가 상당한 파일의 경우 mmap 이 작업을 수행하는 가장 좋은 방법입니다. 기존의 개선 mmap 답변,이 버전은 Windows와 Linux 사이에서 휴대 할 수 있으며 더 빠르게 실행해야합니다 (GB 범위의 파일이있는 32 비트 파이썬에서 일부 수정 없이는 작동하지 않지만 이 처리에 대한 힌트에 대한 다른 답변 및 Python 2에서 작업하기 위해 수정하십시오.).

import io  # Gets consistent version of open for both Py2.7 and Py3.x
import itertools
import mmap

def skip_back_lines(mm, numlines, startidx):
    '''Factored out to simplify handling of n and offset'''
    for _ in itertools.repeat(None, numlines):
        startidx = mm.rfind(b'\n', 0, startidx)
        if startidx < 0:
            break
    return startidx

def tail(f, n, offset=0):
    # Reopen file in binary mode
    with io.open(f.name, 'rb') as binf, mmap.mmap(binf.fileno(), 0, access=mmap.ACCESS_READ) as mm:
        # len(mm) - 1 handles files ending w/newline by getting the prior line
        startofline = skip_back_lines(mm, offset, len(mm) - 1)
        if startofline < 0:
            return []  # Offset lines consumed whole file, nothing to return
            # If using a generator function (yield-ing, see below),
            # this should be a plain return, no empty list

        endoflines = startofline + 1  # Slice end to omit offset lines

        # Find start of lines to capture (add 1 to move from newline to beginning of following line)
        startofline = skip_back_lines(mm, n, startofline) + 1

        # Passing True to splitlines makes it return the list of lines without
        # removing the trailing newline (if any), so list mimics f.readlines()
        return mm[startofline:endoflines].splitlines(True)
        # If Windows style \r\n newlines need to be normalized to \n, and input
        # is ASCII compatible, can normalize newlines with:
        # return mm[startofline:endoflines].replace(os.linesep.encode('ascii'), b'\n').splitlines(True)

이것은 꼬리가 작은 줄의 수가 충분히 작다고 가정합니다. 한 번에 모두 메모리에 안전하게 읽을 수 있습니다. 또한 발전기 기능을 만들고 최종 라인을 대체하여 한 번에 한 줄을 수동으로 읽을 수 있습니다.

        mm.seek(startofline)
        # Call mm.readline n times, or until EOF, whichever comes first
        # Python 3.2 and earlier:
        for line in itertools.islice(iter(mm.readline, b''), n):
            yield line

        # 3.3+:
        yield from itertools.islice(iter(mm.readline, b''), n)

마지막으로, 이것은 이진 모드로 읽습니다 (사용하는 데 필요합니다. mmap) 그래서 그것은 제공합니다 str 라인 (py2) 및 bytes 라인 (py3); 네가 원한다면 unicode (py2) 또는 str (py3), 반복적 인 접근법은 당신을 위해 해독하고/또는 newlines를 고정하기 위해 조정할 수 있습니다.

        lines = itertools.islice(iter(mm.readline, b''), n)
        if f.encoding:  # Decode if the passed file was opened with a specific encoding
            lines = (line.decode(f.encoding) for line in lines)
        if 'b' not in f.mode:  # Fix line breaks if passed file opened in text mode
            lines = (line.replace(os.linesep, '\n') for line in lines)
        # Python 3.2 and earlier:
        for line in lines:
            yield line
        # 3.3+:
        yield from lines

참고 : 테스트 할 파이썬에 액세스 할 수없는 기계 에이 모든 것을 입력했습니다. 내가 뭐든지 유인했다면 알려주세요. 이것은 충분히 비슷했습니다 내 다른 대답 그게 나 생각한다 작동해야하지만 조정 (예 : 처리 offset) 미묘한 오류로 이어질 수 있습니다. 실수가 있으면 의견에 알려주십시오.

S.Lott의 최고 투표 답변 (21:43 년 9 월 25 일)을 기반으로하지만 작은 파일에 대해 수정되었습니다.

def tail(the_file, lines_2find=20):  
    the_file.seek(0, 2)                         #go to end of file
    bytes_in_file = the_file.tell()             
    lines_found, total_bytes_scanned = 0, 0
    while lines_2find+1 > lines_found and bytes_in_file > total_bytes_scanned: 
        byte_block = min(1024, bytes_in_file-total_bytes_scanned)
        the_file.seek(-(byte_block+total_bytes_scanned), 2)
        total_bytes_scanned += byte_block
        lines_found += the_file.read(1024).count('\n')
    the_file.seek(-total_bytes_scanned, 2)
    line_list = list(the_file.readlines())
    return line_list[-lines_2find:]

    #we read at least 21 line breaks from the bottom, block by block for speed
    #21 to ensure we don't get a half line

이것이 유용하기를 바랍니다.

PIP를 사용하여 설치할 수있는 PYPI에는 기존의 꼬리 구현이 있습니다.

  • mtfileutil
  • 멀티 테일
  • log4 tailer
  • ...

상황에 따라 기존 도구 중 하나를 사용하면 이점이있을 수 있습니다.

다음은 매우 간단한 구현입니다.

with open('/etc/passwd', 'r') as f:
  try:
    f.seek(0,2)
    s = ''
    while s.count('\n') < 11:
      cur = f.tell()
      f.seek((cur - 10))
      s = f.read(10) + s
      f.seek((cur - 10))
    print s
  except Exception as e:
    f.readlines()

단순한 :

with open("test.txt") as f:
data = f.readlines()
tail = data[-2:]
print(''.join(tail)

매우 큰 파일의 효율성 (꼬리를 사용하려는 로그 파일 상황에서 일반적으로)의 경우 일반적으로 전체 파일을 읽지 않으려 고합니다 (전체 파일을 한 번에 메모리에 읽지 않고도 수행하더라도). 어떻게 든 캐릭터가 아닌 라인으로 오프셋을 해결해야합니다. 한 가지 가능성은 Char의 Seek () char와 함께 거꾸로 읽는 것이지만 이것은 매우 느립니다. 대신, 더 큰 블록으로 처리하는 것이 좋습니다.

나는 여기에서 사용할 수있는 파일을 뒤로 읽기 위해 얼마 전에 쓴 유틸리티 기능을 사용합니다.

import os, itertools

def rblocks(f, blocksize=4096):
    """Read file as series of blocks from end of file to start.

    The data itself is in normal order, only the order of the blocks is reversed.
    ie. "hello world" -> ["ld","wor", "lo ", "hel"]
    Note that the file must be opened in binary mode.
    """
    if 'b' not in f.mode.lower():
        raise Exception("File must be opened using binary mode.")
    size = os.stat(f.name).st_size
    fullblocks, lastblock = divmod(size, blocksize)

    # The first(end of file) block will be short, since this leaves 
    # the rest aligned on a blocksize boundary.  This may be more 
    # efficient than having the last (first in file) block be short
    f.seek(-lastblock,2)
    yield f.read(lastblock)

    for i in range(fullblocks-1,-1, -1):
        f.seek(i * blocksize)
        yield f.read(blocksize)

def tail(f, nlines):
    buf = ''
    result = []
    for block in rblocks(f):
        buf = block + buf
        lines = buf.splitlines()

        # Return all lines except the first (since may be partial)
        if lines:
            result.extend(lines[1:]) # First line may not be complete
            if(len(result) >= nlines):
                return result[-nlines:]

            buf = lines[0]

    return ([buf]+result)[-nlines:]


f=open('file_to_tail.txt','rb')
for line in tail(f, 20):
    print line

편집] 더 구체적인 버전이 추가되었습니다 (두 번 반전해야합니다)

F.seek (0, 2)로 파일 끝으로 이동 한 다음 readline ()을 대체하는 다음과 같은 줄을 하나씩 읽을 수 있습니다.

def readline_backwards(self, f):
    backline = ''
    last = ''
    while not last == '\n':
        backline = last + backline
        if f.tell() <= 0:
            return backline
        f.seek(-1, 1)
        last = f.read(1)
        f.seek(-1, 1)
    backline = last
    last = ''
    while not last == '\n':
        backline = last + backline
        if f.tell() <= 0:
            return backline
        f.seek(-1, 1)
        last = f.read(1)
        f.seek(-1, 1)
    f.seek(1, 1)
    return backline

Eyecue Answer (Jun 10 '10 at 21:28)를 기반으로 :이 클래스는 객체를 파일에 추가하여 Head () 및 Tail () 메소드를 추가합니다.

class File(file):
    def head(self, lines_2find=1):
        self.seek(0)                            #Rewind file
        return [self.next() for x in xrange(lines_2find)]

    def tail(self, lines_2find=1):  
        self.seek(0, 2)                         #go to end of file
        bytes_in_file = self.tell()             
        lines_found, total_bytes_scanned = 0, 0
        while (lines_2find+1 > lines_found and
               bytes_in_file > total_bytes_scanned): 
            byte_block = min(1024, bytes_in_file-total_bytes_scanned)
            self.seek(-(byte_block+total_bytes_scanned), 2)
            total_bytes_scanned += byte_block
            lines_found += self.read(1024).count('\n')
        self.seek(-total_bytes_scanned, 2)
        line_list = list(self.readlines())
        return line_list[-lines_2find:]

용법:

f = File('path/to/file', 'r')
f.head(3)
f.tail(3)

이러한 솔루션 중 일부에는 파일이 n으로 끝나지 않거나 전체 첫 번째 줄을 읽을 수있는 경우 문제가 있습니다.

def tail(file, n=1, bs=1024):
    f = open(file)
    f.seek(-1,2)
    l = 1-f.read(1).count('\n') # If file doesn't end in \n, count it anyway.
    B = f.tell()
    while n >= l and B > 0:
            block = min(bs, B)
            B -= block
            f.seek(B, 0)
            l += f.read(block).count('\n')
    f.seek(B, 0)
    l = min(l,n) # discard first (incomplete) line if l > n
    lines = f.readlines()[-l:]
    f.close()
    return lines

파일의 마지막 줄에서 특정 값을 읽고이 스레드를 우연히 발견해야했습니다. 파이썬에서 휠을 재창조하는 대신/usr/local/bin/get_last_netp로 저장된 작은 쉘 스크립트로 끝났습니다.

#! /bin/bash
tail -n1 /home/leif/projects/transfer/export.log | awk {'print $14'}

그리고 파이썬 프로그램에서 :

from subprocess import check_output

last_netp = int(check_output("/usr/local/bin/get_last_netp"))

Deque를 사용하는 첫 번째 예제는 아니지만 단순한 예제입니다. 이것은 일반적입니다. 파일뿐만 아니라 반복 가능한 객체에서 작동합니다.

#!/usr/bin/env python
import sys
import collections
def tail(iterable, N):
    deq = collections.deque()
    for thing in iterable:
        if len(deq) >= N:
            deq.popleft()
        deq.append(thing)
    for thing in deq:
        yield thing
if __name__ == '__main__':
    for line in tail(sys.stdin,10):
        sys.stdout.write(line)
This is my version of tailf

import sys, time, os

filename = 'path to file'

try:
    with open(filename) as f:
        size = os.path.getsize(filename)
        if size < 1024:
            s = size
        else:
            s = 999
        f.seek(-s, 2)
        l = f.read()
        print l
        while True:
            line = f.readline()
            if not line:
                time.sleep(1)
                continue
            print line
except IOError:
    pass
import time

attemps = 600
wait_sec = 5
fname = "YOUR_PATH"

with open(fname, "r") as f:
    where = f.tell()
    for i in range(attemps):
        line = f.readline()
        if not line:
            time.sleep(wait_sec)
            f.seek(where)
        else:
            print line, # already has newline
import itertools
fname = 'log.txt'
offset = 5
n = 10
with open(fname) as f:
    n_last_lines = list(reversed([x for x in itertools.islice(f, None)][-(offset+1):-(offset+n+1):-1]))
abc = "2018-06-16 04:45:18.68"
filename = "abc.txt"
with open(filename) as myFile:
    for num, line in enumerate(myFile, 1):
        if abc in line:
            lastline = num
print "last occurance of work at file is in "+str(lastline) 

There is very useful module that can do this:

from file_read_backwards import FileReadBackwards

with FileReadBackwards("/tmp/file", encoding="utf-8") as frb:

# getting lines by lines starting from the last line up
for l in frb:
    print(l)

On second thought, this is probably just as fast as anything here.

def tail( f, window=20 ):
    lines= ['']*window
    count= 0
    for l in f:
        lines[count%window]= l
        count += 1
    print lines[count%window:], lines[:count%window]

It's a lot simpler. And it does seem to rip along at a good pace.

I found a probably the easiest way to find the first or last N lines of a file

Last N lines of a file(For Ex:N=10)

file=open("xyz.txt",'r")
liner=file.readlines()
for ran in range((len(liner)-N),len(liner)):
    print liner[ran]

First N lines of a file(For Ex:N=10)

file=open("xyz.txt",'r")
liner=file.readlines()
for ran in range(0,N+1):
    print liner[ran]

it's so simple:

def tail(fname,nl):
with open(fname) as f:
    data=f.readlines() #readlines return a list
    print(''.join(data[-nl:]))

Although this isn't really on the efficient side with big files, this code is pretty straight-forward:

  1. It reads the file object, f.
  2. It splits the string returned using newlines, \n.
  3. It gets the array lists last indexes, using the negative sign to stand for the last indexes, and the : to get a subarray.

    def tail(f,n):
        return "\n".join(f.read().split("\n")[-n:])
    
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top