【问题标题】:Does unix utility tail read through the whole file?unix 实用程序尾部是否会读取整个文件?
【发布时间】:2015-07-05 00:51:52
【问题描述】:

我使用带有选项 -f 的 tail 实用程序来查看我的一个日志文件。我的 CGI 程序总是只将日志文件的最后 40 行发送到我的网页,在那里我可以实时监控日志并发出声音通知。现在我只想发送满足某些条件的最后 40 行,例如。匹配任何模式。我想我必须使用 grep,但我怎样才能只选择最后 40 个匹配行?我必须用两次“尾巴”吗?

【问题讨论】:

    标签: design-patterns filter grep cgi tail


    【解决方案1】:
    grep condition file | tail -40
    

    如果这不是您想要的,请编辑您的问题以显示一些示例输入和预期输出(虽然不是 40 多行)。

    https://stackoverflow.com/a/31220727/1745001 下的 cmets 中讨论性能:在 1M 行文件上,其中“bar”出现 1,000 次,并且每隔一行只是由该脚本创建的“foo”:

     awk 'BEGIN{for (i=1;i<=1000000;i++) print (i%1000 ? "foo" : "bar")}' > file
    

    这里是cygwin下bash 4.3.33的第三次运行时间:

    $ time (grep bar file | tail -40) >/dev/null
    real    0m0.050s
    user    0m0.030s
    sys     0m0.045s
    
    $ time (tac file | grep bar | head -40 | tac) >/dev/null
    real    0m0.100s
    user    0m0.061s
    sys     0m0.107s
    
    $ time (tac file | grep -m 40 bar | tac) >/dev/null
    real    0m0.080s
    user    0m0.000s
    sys     0m0.090s
    

    在由以下人员创建的 100M 文件上:

    awk 'BEGIN{for (i=1;i<=100000000;i++) print (i%1000 ? "foo" : "bar")}' > file
    

    我明白了:

    $ time (grep bar file | tail -40) >/dev/null
    real    0m1.014s
    user    0m0.841s
    sys     0m0.202s
    
    $ time (tac file | grep bar | head -40 | tac) >/dev/null
    real    0m1.154s
    user    0m1.262s
    sys     0m0.248s
    
    $ time (tac file | grep -m 40 bar | tac) >/dev/null
    real    0m0.078s
    user    0m0.015s
    sys     0m0.046s
    

    完全符合预期。对于前两个,grep 在搜索整个文件时执行完全相同的处理,这是驱动大部分持续时间的原因,工作负载的唯一区别是 tailtac+pipe+head+pipe+tac,而第三个 grep 是因为它在第 40 场比赛后退出,所以工作量要少得多,因此整个管道更快。

    【讨论】:

    • 当我重现你的实验时,我在 grep&tail 与 tac&grep&head&tac 上得到相同的数字。但是当我将其应用于真实数据时,tac 方式要快得多。可能生成的文件不够大?
    • 在 awk 生成脚本中添加了三个零,并获得了更好的 tac 性能
    • 您确定将时间参数括在括号中以便整个管道的时间?当您在原始管道上运行时间时,结果未指定,因此您的结果可能是比较 tac filegrep bar file 的时间,而不是比较整个管道。
    • 尝试了封闭和不封闭,没有区别。还尝试了 grepping foo(错误?),差异变大了。
    • 我不想等待来自 1,000M 行文件的结果,所以我尝试使用 100M 行文件并再次得到完全预期的结果,见上文。对于为什么tac file | grep bar | head -40 | tac 会比grep bar file | tail -40 更快,你有什么合乎逻辑的解释吗?我只是无法从逻辑上理解为什么会这样,当然我得到的结果是不是。
    【解决方案2】:
    tac file | grep "your regexp here" | head -40 | tac
    
    time (grep bar file | tail -40) >/dev/null
    real    0m15.472s
    user    0m15.316s
    sys     0m0.172s
    
    time (tac file | grep bar | head -40 | tac) >/dev/null
    real    0m0.146s
    user    0m0.184s
    sys     0m0.004s
    
    time (tac file | grep -m40 bar | tac) >/dev/null
    real    0m0.005s
    user    0m0.000s
    sys     0m0.000s
    

    发现了一个别名grep="grep -P",所以这是干净的 grep 结果:

    time ("grep" bar file | tail -40) >/dev/null
    
    real    0m1.316s
    user    0m1.164s
    sys     0m0.172s
    
    time (tac file | "grep" bar | head -40 | tac) >/dev/null
    real    0m0.071s
    user    0m0.040s
    sys     0m0.092s
    
    time (tac file | "grep" -m40 bar | tac) >/dev/null
    real    0m0.042s
    user    0m0.004s
    sys     0m0.056s
    

    【讨论】:

    • 您在末尾缺少额外的 | tac 以将行恢复到原来的顺序,唯一有意义的方法就是将 grep "your regexp here" | head -40 替换为grep -m 40 "your regexp here" 所以 grep 不必搜索整个文件,但是你仍然要添加整个文件的 tac 和最后 40 行的 tac ,所以如果它真的能提高性能grep .. | tail.
    • cat file | grep 1000 更改为 grep 1000 file。您永远不需要使用 cat 来打开另一个工具的文件 - google UUOC。您没有说文件有多大或1000 出现在其中的次数。另外,在收集统计信息以消除缓存问题之前,您是否运行了每个命令 3 次?如果1000 频繁出现在输入文件中并且输入文件很大,那么您应该会看到grep -m 40 1000 filegrep 1000 file | head -40 相比有显着的性能提升。
    • 我知道缓存文件的问题,所以试了3次,是的。
    • 好的,然后摆脱 UUOC 并重试并告诉我们输入文件的大小、1000 出现的频率等。
    • UUOC 不会影响性能,所以这是一个品味问题。大小约80mb,约150万行,1000出现4.5k次。
    猜你喜欢
    • 2018-12-29
    • 1970-01-01
    • 2019-10-02
    • 2010-12-30
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2011-11-16
    相关资源
    最近更新 更多