通过中间带有“...”的管道打印文件的前几行和后几​​行

Print first few and last few lines of file through a pipe with "..." in the middle

问题描述

这是我的文件

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:

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

输出:

1
2
...
9
10

您可以考虑这个 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

一个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就是一个pass:

awk -v head=2 -v tail=2 'FNR<=head
{lines[FNR]=[=12=]}
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 秒,'caveman' 方法是 2 ms.

然后我用 seq 99999999 >file

创建了一个 1.1 GB 的文件
  • 两遍awk:50秒
  • 一次 perl:10 秒
  • 一次通过 awk:29 秒
  • 'Caveman': 2 毫秒

两个单通sed解法:

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

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

假设:

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

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

h=2 t=3

cat temp | awk -v head=${h} -v tail=${t} '
    { if (NR <= head) print [=10=]
      lines[NR % tail] = [=10=]
    }

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

这是否是 'correct' 输出将取决于 OP 的要求。