unix – 文件头和尾部

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

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

您可以简单地:

(head; tail) < file.txt 

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

edstandard text editor

 $ echo -e '1+10,$-10d\n%p' | ed -s file.txt 

对于纯stream(例如,从命令输出),可以使用“tee”来分stream,并发送一个stream头和尾。 这需要使用bash(+ / dev / fd / N)的'>(list)'特性:

 ( COMMAND | tee /dev/fd/3 | head ) 3> >( tail ) 

或使用/ dev / fd / N(或/ dev / stderr)加上带有复杂redirect的子机壳:

 ( ( 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 

(这些都不能在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;' 

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

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

如果你想在一个命令中做到这一点(并使它与任何偏移量一起工作,并且不重复行,如果它们重叠),你将不得不效仿我提到的这种行为。

试试这个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 

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

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

那么,你可以随时链接在一起。 像这样, head fiename_foo && tail filename_foo 。 如果这还不够,你可以在.profile文件或者你使用的任何login文件中写一个bash函数:

 head_and_tail() { head $1 && tail $1 } 

然后,从shell提示中调用它: head_and_tail filename_foo

file.ext的前10行,然后是最后10行:

cat file.ext | head -10 && cat file.ext | tail -10

文件的最后10行,然后是前10行:

cat file.ext | tail -10 && cat file.ext | head -10

然后你可以在别处输出输出:

(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program

为什么不使用sed来完成这个任务?

sed -n -e 1,+9p -e 190,+9p textfile.txt

我写了一个简单的Python应用程序来执行此操作: https : //gist.github.com/garyvdm/9970522

它处理pipe道(stream)以及文件。

借鉴上面的想法(testingbash&zsh)

但使用别名'帽子'头和尾巴

 alias hat='(head -5 && echo "^^^------vvv" && tail -5) < ' hat large.sql 

根据JF Sebastian的评论 :

 cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1 

这样,您可以在一个pipe道中以不同的方式处理第一行和其他内容,这对于处理CSV数据非常有用:

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

要处理pipe道(stream)以及文件,请将其添加到.bashrc或.profile文件中:

 headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' ; } 

那么你不仅可以

 headtail 10 < file.txt 

但也

 a.out | headtail 10 

(当input10的长度超过input的长度时,这仍会附加虚假的空白行,不像普通的老的a.out | (head; tail) ,谢谢你以前的回答。

注意: headtail 10 ,不是headtail -10

这个解决scheme花费了大量时间,而这个解决scheme似乎是唯一覆盖所有用例的解决scheme(到目前为止):

 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]} }' 

function列表:

  • 活的输出为头(显然,对于尾巴是不可能的)
  • 不使用外部文件
  • MAX_LINES之后每行的进度条一个点,对于长时间运行的任务非常有用。
  • stderr上的进度条,确保进度点与头部+尾部分开(如果要pipe道输出,非常方便)
  • 避免由于缓冲而导致的错误日志顺序(stdbuf)
  • 当总行数小于head + tail时避免重复输出。
 (sed -u 10q; echo ...; tail) < file.txt 

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

我一直在寻找这个解决scheme。 用sed自己试了一下,但事先不知道文件/stream的长度的问题是无法解决的。 在上面提供的所有选项中,我喜欢Camille Goudeseune的awk解决scheme。 他确实注意到他的解决scheme在输出中留下了额外的空白行,而且数据集足够小。 在这里我提供了他的解决scheme的修改,删除多余的行。

 headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { a_count=0; for (i in a) {a_count++}; for (i=NR-a_count+1; i<=NR; i++) print a[i] }' ; }