unix - 文件的头和尾

时间:2011-12-24 12:59:07

标签: linux bash shell unix scripting

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

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

20 个答案:

答案 0 :(得分:181)

你可以简单地说:

(head; tail) < file.txt

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

cat file.txt | (head; tail)

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

答案 1 :(得分:17)

edstandard text editor

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

答案 2 :(得分:11)

对于纯流(例如,从命令输出),您可以使用'tee'来分叉流并将一个流发送到head和one到tail。这需要使用bash的'&gt;(列表)'功能(+ / dev / fd / N):

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

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

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

答案 3 :(得分:4)

(sed -u 10q; echo ...; tail) < file.txt

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

答案 4 :(得分:3)

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

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

答案 5 :(得分:2)

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

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

答案 6 :(得分:2)

基于J.F. Sebastian's comment

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

通过这种方式,您可以在一个管道中处理第一行和其他行,这对于处理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

答案 7 :(得分:2)

花了很多时间来结束这个解决方案,似乎是唯一一个涵盖所有用例的解决方案(到目前为止):

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

功能列表:

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

答案 8 :(得分:1)

嗯,你总是可以将它们连在一起。像这样, head fiename_foo && tail filename_foo。如果这还不够,您可以在.profile文件或您使用的任何登录文件中自己编写一个bash函数:

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

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

答案 9 :(得分:1)

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

答案 10 :(得分:1)

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

它处理管道(流)和文件。

答案 11 :(得分:0)

使用stdin,但简单易用,可用于99%的用例

head_and_tail

#!/usr/bin/env bash
COUNT=${1:-10}
IT=$(cat /dev/stdin)
echo "$IT" | head -n$COUNT
echo "..."
echo "$IT" | tail -n$COUNT

示例

$ seq 100 | head_and_tail 4
1
2
3
4
...
97
98
99
100

答案 12 :(得分:0)

我会说,取决于文件的大小,主动读取其内容可能不是理想的。在这种情况下,我认为一些简单的shell脚本就足够了。

这是我最近处理大量我正在分析的CSV文件的方式:

$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done

这会打印出每个文件的前10行和后10行,同时还会打印出文件名和前后的省略号。

对于单个大文件,您可以简单地运行以下命令以达到相同的效果:

$ head somefile.csv && echo ... && tail somefile.csv

答案 13 :(得分:0)

sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"

注意 aFile 变量包含文件的完整路径

答案 14 :(得分:0)

要打印文件的前10行和后10行,您可以尝试以下操作:

cat <(head -n10 file.txt) <(tail -n10 file.txt) | less

答案 15 :(得分:0)

在@Samus_解释here关于@Aleksandra Zalcman命令的工作原理的基础上,当你无法快速发现尾部开始的位置而不计算线条时,这种变化很方便。

{ head; echo "####################\n...\n####################"; tail; } < file.txt

或者,如果您开始使用20行以外的其他内容,则行数可能会有所帮助。

{ head -n 18; tail -n 14; } < file.txt | cat -n

答案 16 :(得分:0)

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

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

答案 17 :(得分:0)

借鉴上述想法(测试bash&amp; zsh)

但使用别名&#39;帽子&#39;头和尾巴

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


hat large.sql

答案 18 :(得分:0)

要处理管道(流)和文件,请将其添加到.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

(当10超过输入的长度时,这仍会附加虚假的空白行,与普通的a.out | (head; tail)不同。谢谢,以前的回答者。)

注意:headtail 10,而不是headtail -10

答案 19 :(得分:0)

为什么不使用sed执行此任务?

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