【问题标题】:Print first few and last few lines of file through a pipe with "..." in the middle通过中间带有“...”的管道打印文件的前几行和最后几行
【发布时间】:2021-12-07 21:03:52
【问题描述】:

问题描述

这是我的文件

1
2
3
4
5
6
7
8
9
10

我想通过管道发送这个文件的 cat 输出并接收它

% cat file | some_command
1
2
...
9
10

尝试的解决方案

这是我尝试过的一些解决方案,以及它们的输出

% cat temp | (head -n2 && echo '...' && tail -n2)
1
2
...
% cat temp | tee >(head -n3) >(tail -n3) >/dev/null
1
2
3
8
9
10
# I don't know how to get the ...
% cat temp | sed -e 1b -e '$!d'
1
10

% cat temp | awk 'NR==1;END{print}'
1
10
# Can only get 2 lines

【问题讨论】:

    标签: bash shell tail


    【解决方案1】:

    一个 awk:

    awk -v head=2 -v tail=2 'FNR==NR && FNR<=head
    FNR==NR && cnt++==head {print "..."}
    NR>FNR && FNR>(cnt-tail)' file file
    

    或者如果单次通过很重要(并且内存允许),您可以使用perl

    perl -0777 -lanE 'BEGIN{$head=2; $tail=2;}
    END{say join("\n", @F[0..$head-1],("..."),@F[-$tail..-1]);}' file   
    

    或者,一次通过的 awk:

    awk -v head=2 -v tail=2 'FNR<=head
    {lines[FNR]=$0}
    END{
        print "..."
        for (i=FNR-tail+1; i<=FNR; i++) print lines[i]
    }' file
    

    或者,像这样直接成为穴居人并没有错:

    head -2 file; echo "..."; tail -2 file
    

    任何这些印刷品:

    1
    2
    ...
    9
    10
    

    效率,这里有一些统计数据。

    对于小文件(即小于 10 MB 左右),所有这些都小于 1 秒,而“穴居人”方法是 2 毫秒

    然后我用seq 99999999 &gt;file创建了一个1.1 GB的文件

    • 两次通过 awk:50 秒
    • perl 一次通过:10 秒
    • 一次 awk:29 秒
    • “穴居人”:2 毫秒

    【讨论】:

    • 现在处理行数小于头尾的情况,以及头尾线相交的情况^^
    • 它们都处理重叠的头部和尾部。
    • 特别是对于大文件,“穴居人”方法是最好的,因为它是唯一不会读取整个文件的方法(head 在几行后停止,tail 寻找到最后并返回)。尝试perl 版本,其文件大于可用 RAM,您会大吃一惊。
    • @dawg,我认为通过重叠头部和尾部,它们的意思是例如文件只有三行的情况。给定三行 123,最后一个 head+tail 解决方案将打印 12...2、@987654340至少对于问题的某些措辞可能在技术上是正确的,但它也可能被认为具有误导性。看起来其他的打印一样。
    • @dawg,在这个 Q 的狭隘背景下,我们不知道,因为帖子没有说。但更一般地说,1\n2\n...\n2\n3 意味着在它显示... 的部分中删除了某些内容,而对于三行或四行文件则不是这样。对我来说,按原样打印一个三行文件,没有省略号会更有意义。 一般。当然,我们不知道他们在这种特殊情况下在做什么,如果有一个用例需要/期望所有四行和...,并且加倍的2 行是有意义的,那么需要完成。
    【解决方案2】:

    你可以考虑这个 awk 解决方案:

    awk -v top=2 -v bot=2 'FNR == NR {++n; next} FNR <= top || FNR > n-top; FNR == top+1 {print "..."}' file{,}
    
    1
    2
    ...
    9
    10
    

    【讨论】:

      【解决方案3】:

      两个单通sed解决方案:

      sed '1,2b
           3c\
      ...
           N
           $!D'
      

      sed '1,2b
           3c\
      ...
           $!{h;d;}
           H;g'
      

      【讨论】:

      • 这是如何工作的?如果您评论代码并说明您正在使用模式/保持空间做什么,那么对于有相关问题(例如计数不是 2)的未来读者会更有帮助。
      【解决方案4】:

      假设:

      • 正如 OP 所述,解决方案必须能够处理来自管道的流
      • 来自流的总行数未知
      • 如果总行数小于head/tail 偏移的总和,那么我们将打印重复行(如果 OP 更新问题并提供有关如何解决这种情况的更多详细信息,我们可以添加更多逻辑)李>

      implements a queue in awk 跟踪最近的 N 行的单程 awk 解决方案;队列允许我们将 awk's 内存使用限制为仅 N 行(而不是将整个输入流加载到内存中,这在可用内存有限的机器上处理大量行/数据时可能会出现问题):

      h=2 t=3
      
      cat temp | awk -v head=${h} -v tail=${t} '
          { if (NR <= head) print $0
            lines[NR % tail] = $0
          }
      
      END { print "..."
      
            if (NR < tail) i=0
            else           i=NR
      
            do { i=(i+1)%tail
                 print lines[i]
               } while (i != (NR % tail) )
          }'
      

      这会生成:

      1
      2
      ...
      8
      9
      10
      

      演示重叠问题:

      $ cat temp4
      1
      2
      3
      4
      

      使用h=3;t=3 建议的awk 代码生成:

      $ cat temp4 | awk -v head=${h} -v tail=${t} '...'
      1
      2
      3
      ...
      2
      3
      4
      

      这是否是“正确”的输出将取决于 OP 的要求。

      【讨论】:

        【解决方案5】:

        我建议bash:

        (head -n 2; echo "..."; tail -n 2) < file
        

        输出:

        1 2 ... 9 10

        【讨论】:

        • 为什么 OP 的 cat temp | (head &amp;&amp; echo &amp;&amp; tail) 解决方案不起作用?
        • 看起来head 在这两种情况下都从输入中过度读取,然后尝试向后lseek。如果 file 被重定向,那么这有效,但如果输入是管道,则无效。我很好奇依赖这种行为的便携性。它只是碰巧在这里工作,还是在 POSIX 中保证行为?
        • @JohnKugelman:我无法回答你的问题。
        • @JohnKugelman 这可能是对 MacOS Monteray 的依赖或设置的问题,因为我认为这个解决方案曾经对我有用
        • @Cyrus 需要通过管道,n 后面加一个空格没有区别
        猜你喜欢
        • 1970-01-01
        • 2015-03-05
        • 2023-03-17
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多