单行:打印除最后3行以外的所有行?

时间:2013-09-20 18:04:44

标签: linux perl bash freebsd

我想模拟GNU的head -n -3,它打印除了最后3行之外的所有行,因为FreeBSD上的head没有此功能。所以我想的是像

这样的东西
seq 1 10 | perl -ne ...

这里我使用了10行,但它可以是任何大于3的数字。

可以用Perl或其他方式在BASH的FreeBSD上完成吗?

超级原始解决方案

seq 1 10 | sed '$d' | sed '$d' | sed '$d'

10 个答案:

答案 0 :(得分:11)

seq 1 10 | perl -e '@x=("")x3;while(<>){print shift @x;push @x,$_}'

perl -e '@x=("")x3;while(<>){print shift @x;push @x,$_}' file

command | perl -pe 'BEGIN{@x=("")x3}push @x,$_;$_=shift @x'
perl -pe 'BEGIN{@x=("")x3}push @x,$_;$_=shift @x' file

答案 1 :(得分:9)

seq 1 10 | perl -ne 'push @l, $_; print shift @l if @l > 3'

答案 2 :(得分:7)

纯粹的bash和简单的工具(wc和cut):

head -n $(($(wc -l file | cut -c-8)-3)) file

免责声明 - 我现在无法访问FreeBSD,但这适用于OSX bash。

答案 3 :(得分:6)

这适用于管道和输入文件:

seq 1 10 | perl -e'@x=<>;print@x[0..$#x-3]'

答案 4 :(得分:5)

似乎没有人使用sedtac,所以这里有一个:

$ seq 10 | tac | sed '1,3d' | tac
1
2
3
4
5
6
7

答案 5 :(得分:2)

怎么样:

 seq 1 10 | perl -ne 'print if ( !eof  )' | perl -ne 'print if ( !eof  )' | perl -ne 'print if ( !eof  )' 

答案 6 :(得分:2)

这个awk单行似乎做了这个工作:

awk '{a[NR%4]=$0}NR>3{print a[(NR-3)%4]}' file

答案 7 :(得分:1)

如果您使用的是4.0或更高版本,请单独使用bash:

seq 1 10 | (readarray -t LINES; printf '%s\n' "${LINES[@]:(-3)}")

更新:这一行将删除最后三行而不是仅显示它们。

seq 1 10 | (readarray -t L; C=${#L[@]}; printf '%s\n' "${L[@]:0:(C > 3 ? C - 3 : 0)}")

为方便起见,它可以放在一个函数上:

function exclude_last_three {
    local L C
    readarray -t L; C=${#L[@]}
    printf '%s\n' "${L[@]:0:(C > 3 ? C - 3 : 0)}"
}

seq 1 10  | exclude_last_three
seq 11 20 | exclude_last_three

答案 8 :(得分:1)

这是一个迟到的答案,因为我昨天遇到了这样的事情。

此解决方案是:

  • pure bash
  • 单行
  • 只读取一次输入流
  • 逐行读取输入流,而不是一次读取

在Ubuntu,Redhat和OSX上测试过。

$ seq 1 10 | { n=3; i=1; while IFS= read -r ln; do [ $i -gt $n ] && cat <<< "${buf[$((i%n))]}"; buf[$((i%n))]="$ln"; ((i++)); done; }
1
2
3
4
5
6
7
$ 

通过将行读入实现为n元素数组的循环缓冲区来工作。

n是切断文件末尾的行数。

对于我们读取的每一行,我们可以从循环缓冲区回显行i-n,然后将行i存储在循环缓冲区中。在读取前n行之前,不会回显任何内容。 (i mod n)是实现循环缓冲区的数组的索引。

因为要求是单行,所以我试图使其相当简短,不幸的是以牺牲可读性为代价。

答案 9 :(得分:0)

另一种Awk解决方案,它只使用最少量的缓冲区并快速打印线条,而无需先读取所有行。它也可以用于管道和大文件。

awk 'BEGIN{X = 3; for(i = 0; i < X; ++i)getline a[i]}{i %= X; print a[i]; a[i++] = $0}'