使用lua模拟tail -n命令读取最后n行

最近需要使用lua读取文件的最后n行数据,但不想调用linux中的tail命令来获取,于是使用纯lua来实现。

实现思路

  1. 把文件指针偏移距离文件尾x个字节
  2. 读取x个字节数据
  3. 在这x个字节数据中查找换行符\n,如果找到n个换行符,把文件指针偏移到第n个换行符的位置,输出全部内容
  4. 如果找不到足够的换行符,继续把文件指针在当前位置向文件头方向偏移x个字节
  5. 返回2步骤循环,直到找到足够换行符或到文件头

lua代码

tail.lua

#!/usr/bin/lua

if arg[1] == "-n" then
    tail_lines = arg[2]
    filepath = arg[3]
else
    tail_lines = 10
    filepath = arg[1]
end

-- 一次读取512字节数据
read_byte_once = 512
offset = 0
fp = io.open(filepath,"r")
if fp == nil then
    print("open file "..filepath.." failed.")
    os.exit(0)
end
line_num = 0
while true do
    -- 每次偏移read_byte_once字节
    offset = offset - read_byte_once
    -- 以文件尾为基准偏移offset
    if fp:seek("end",offset) == nil then
        -- 偏移超出文件头后将出错,这时如果是第一次读取的话,直接将文件指针偏移到头部,否则跳出循环输出所有内容
        if offset + read_byte_once == 0 then
            fp:seek("set")
        else
            break
        end
    end
    data = fp:read(read_byte_once)
    -- 倒转数据,方便使用find方法来从尾读取换行符
    data = data:reverse()
    index = 1
    while true do
        -- 查找换行符
        start = data:find("\n",index, true)
        if start == nil then
            break
        end
        -- 找到换行符累加
        line_num = line_num + 1
        -- 找到足够换行符
        if tail_lines + 1 == line_num then
            -- 偏移文件符指针到第line_num个换行符处
            fp:seek("end",offset+read_byte_once-start+1)
            io.write(fp:read("*all"))
            fp:close()
            os.exit(0)
        end
        index = start + 1
    end
end

-- 找不到足够的行,就输出全部
fp:seek("set")
io.write(fp:read("*all"))
fp:close() 

用法

读取centos.log最后10行

./tail.lua centos.log

读取centos.log最后20行

./tail.lua -n 20 centos.log
标签:LUA 发布于:2019-11-18 09:58:42