unix - 文件的头和尾

too*_*oop 124 unix linux bash shell scripting

假设您有一个txt文件,同时查看前10行和后10行文件的命令是什么?

即如果文件长度为200行,则一次查看1-10行和190-200行.

Ale*_*man 194

你可以简单地说:

(head; tail) < file.txt
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因需要使用管道,那么像这样:

cat file.txt | (head; tail)
Run Code Online (Sandbox Code Playgroud)

注意:如果file.txt中的行数小于head的默认行+ tail的默认行,则会打印重复的行.

  • 严格地说,这不会给你原始文件的尾部,但是`head`之后的流的尾部消耗了文件的前10行.(将此与`head <file.txt; tail <file.txt`比较少于20行的文件).请记住一个非常小的问题.(但仍然是+1.) (51认同)
  • +1从未意识到这样的语法是可能的 (24认同)
  • 很抱歉,但答案仅适用于某些情况.`seq 100 | (头;尾)`只给我前10个数字.只有在更大的输入大小(如`seq 2000`)上,尾部才能得到一些输入. (17认同)
  • 尼斯.如果你想在头部和尾部之间留一个间隙:(头部;回声;尾部)<file.txt (14认同)
  • @nametal实际上,你甚至可能没那么多.虽然`head`只*显示*输入的前10行,但不能保证它不会*消耗*更多它以便找到第10行结束,留下更少的输入`less`显示. (9认同)
  • 注意:缓冲问题(头部从小文件的输入流中吞下太多,因此不会打印尾部)通过以下答案解决:`cat file.txt | (sed -u 10q ; echo ; tail)` (6认同)
  • @alkar @JFSebastian `seq 100 | { 三通 &gt;(头 &gt;&amp;2) | 尾巴; } 2&gt;&amp;1;` 也可以避免我们不知道流消耗了多少 head 的问题 (5认同)
  • 好奇为什么/如何运作.被问到这是一个新问题:http://stackoverflow.com/questions/13718242/ (3认同)
  • @chepner:[`{ T 恤 &gt;(head &gt;&amp;2) | 尾巴; } 2&gt;&amp;1 &lt; file.txt` 而不是 `{ head; 尾巴; 如果需要,&lt; file.txt` 支持重叠行](http://stackoverflow.com/a/20388399/4279)。使用“{}”代替“()”是为了避免创建子shell。 (2认同)

kev*_*kev 18

ed 是个 standard text editor

$ echo -e '1+10,$-10d\n%p' | ed -s file.txt
Run Code Online (Sandbox Code Playgroud)

  • 如果文件多于或少于200行怎么办?你不知道从头开始的行数? (2认同)

小智 13

对于纯流(例如,来自命令的输出),您可以使用'tee'来分叉流并将一个流发送到头部和一个到尾部.这需要使用bash(+/dev/fd/N)的'>(list)'功能:

( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )
Run Code Online (Sandbox Code Playgroud)

或使用/ dev/fd/N(或/ dev/stderr)加上具有复杂重定向的子壳:

( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1
( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1
Run Code Online (Sandbox Code Playgroud)

(这些都不适用于csh或tcsh.)

对于具有更好控制的东西,您可以使用此perl命令:

COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,它打破了大于缓冲区大小的文件(在我的系统上为8K).`cat>/dev/null`修复它:`COMMAND | {tee>(head>&2; cat>/dev/null)| 尾巴; } |&other_commands` (2认同)

mod*_*lar 7

基于JF 塞巴斯蒂安的评论

cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以在一个管道中以不同的方式处理第一行和其余行,这对于处理 CSV 数据非常有用:

{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
Run Code Online (Sandbox Code Playgroud)
N*2
2
4
6


sor*_*rin 6

我们花了很多时间才最终完成这个解决方案,该解决方案似乎是唯一涵盖所有用例的解决方案(到目前为止):

command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
          '{
               if (NR <= offset) print;
               else {
                   a[NR] = $0;
                   delete a[NR-offset];
                   printf "." > "/dev/stderr"
                   }
           }
           END {
             print "" > "/dev/stderr";
             for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++)
             { print a[i]}
           }'
Run Code Online (Sandbox Code Playgroud)

功能列表:

  • 头部的实时输出(显然尾部的实时输出是不可能的)
  • 不使用外部文件
  • 进度条在 MAX_LINES 之后每行一个点,对于长时间运行的任务非常有用。
  • stderr 上的进度条,确保进度点与 head+tail 分开(如果您想通过管道传输 stdout,非常方便)
  • 避免由于缓冲(stdbuf)而可能出现的错误记录顺序
  • 当总行数小于 head + tail 时,避免重复输出。


小智 6

(sed -u 10q; echo ...; tail) < file.txt
Run Code Online (Sandbox Code Playgroud)

(head;tail)主题的另一个变体,但是避免了小文件的初始缓冲区填充问题。


mah*_*mah 5

head -10 file.txt; tail -10 file.txt

除此之外,您需要编写自己的程序/脚本。

  • 或者,无需生成子shell:`{ head file; 尾文件;} | prog`(大括号内的间距,并且需要尾随分号) (3认同)

Sam*_*us_ 5

这里的问题是面向流的程序事先不知道文件的长度(因为如果它是真正的流,则可能没有文件的长度)。

tail诸如缓冲看到的最后 n 行并等待流结束,然后打印之类的工具。

如果您想在单个命令中执行此操作(并使其适用于任何偏移量,并且如果重叠,则不要重复行),您将必须模拟我提到的这种行为。

试试这个 awk:

awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile
Run Code Online (Sandbox Code Playgroud)