unix

时间:2015-05-13 01:38:10

标签: unix logging pipeline tail

我正在努力想出一个unix命令管道,它允许我只将程序输出的最新 n 行记录到文本文件中。

文本文件的长度不应超过 n 。 (首次填写文件时可能会少一些)

它将在内存/资源有限的设备上运行,因此保持文件大小是一个优先事项。

我尝过这样的东西(n = 500):

program_spitting_out_text > output.txt
cat output.txt | tail -500 > recent_output.txt
rm output.txt

program_spitting_out_text | tee output.txt | tail -500 > recent_output.txt

显然两件都不适合我的目的......

任何人都有一个很好的方法在单行中做到这一点?或者我是否必须编写脚本/实用程序?

注意:我不想与dmesg有任何关系,必须使用标准的BSD unix命令。 “program_spitting_out_text”每秒打印约60行/秒。

提前致谢!

1 个答案:

答案 0 :(得分:2)

如果program_spitting_out_text持续运行并保持文件打开,那么你可以做很多事情。

即使删除文件也无济于事,因为它仍会继续写入现在的“隐藏”文件(数据仍然存在,但没有目录条目),直到它关闭它,此时它将真的除去。

如果它关闭并定期重新打开日志文件(每行或每十秒或其他),那么你有一个相对容易的选择。

只需监控文件,直到达到一定的大小,然后滚动文件,例如:

while true; do
    sleep 5
    lines=$(wc -l <file.log)
    if [[ $lines -ge 5000 ]]; then
        rm -f file2.log
        mv file.log file2.log
        touch file.log
    fi
done

此脚本将每五秒检查一次文件,如果是5000行或更多,则会将其移动到备份文件。写入它的程序将继续写入该备份文件(因为它具有打开的句柄),直到它关闭它,然后它将重新打开新文件。

这意味着您将在日志文件集中始终拥有(大致)五到一万行,并且您可以使用组合这两行的命令搜索它们:

grep ERROR file2.log file.log

另一种可能性是,如果您可以定期重新启动程序而不影响其功能。举例来说,可以在没有问题的情况下重新启动一个程序,该程序每秒查找一次文件的存在并报告该文件。一个计算PI到一千亿有效数字的人可能可以在没有影响的情况下重新启动。

如果 可重启,那么你基本上可以采用与上面相同的技巧。当日志文件达到一定大小时,杀死当前程序(您将从脚本中作为后台任务启动),在滚动日志文件时执行所需的任何魔术,然后重新启动程序。

例如,考虑以下(可重启)程序prog.sh,它只是连续输出当前日期和时间:

#!/usr/bin/bash
while true; do
    date
done

然后,以下脚本将负责根据需要启动和停止其他脚本,方法是每隔五秒检查一次日志文件,看它是否超出了限制:

#!/usr/bin/bash

exe=./prog.sh
log1=prog.log
maxsz=500

pid=-1
touch ${log1}
log2=${log1}-prev

while true; do
    if [[ ${pid} -eq -1 ]]; then
        lines=${maxsz}
    else
        lines=$(wc -l <${log1})
    fi
    if [[ ${lines} -ge ${maxsz} ]]; then
        if [[ $pid -ge 0 ]]; then
            kill $pid >/dev/null 2>&1
        fi
        sleep 1
        rm -f ${log2}
        mv ${log1} ${log2}
        touch ${log1}
        ${exe} >> ${log1} &
        pid=$!
    fi
    sleep 5
done

此输出(来自两个日志文件中的每秒wc -l)显示切换时发生的情况,并指出它仅是近似值,因为切换涉及延迟:

474 prog.log       0 prog.log-prev
496 prog.log       0 prog.log-prev
518 prog.log       0 prog.log-prev
539 prog.log       0 prog.log-prev
542 prog.log       0 prog.log-prev
 21 prog.log     542 prog.log-prev

现在请记住这是一个示例脚本。它相对智能,但可能需要一些错误处理,以便在关闭监视器时不会使可执行文件继续运行。

最后,如果这些都不够,那么就没有什么可以阻止你编写自己的过滤程序,该程序接受标准输入并连续输出到真正的环形缓冲区文件。

然后你会做:

program_spitting_out_text | ringbuffer 4096 last4k.log

该程序可能是一个真正的环形缓冲区,因为它将4k文件视为循环字符缓冲区,但是,当然,您需要在文件中使用特殊标记来指示写入点,以及程序可以把它变回真正的流。

或者,它可以与上面的脚本完全相同,重写文件,使其始终低于所需的大小。