8

我想模拟 GNU's head -n -3,它会打印除最后 3 行之外的所有行,因为head在 FreeBSD 上没有此功能。所以我在想类似的东西

seq 1 10 | perl -ne ...

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

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

一个超级原始的解决方案是

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

10 回答 10

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
于 2013-09-20T18:11:25.200 回答
9
seq 1 10 | perl -ne 'push @l, $_; print shift @l if @l > 3'
于 2013-09-21T00:06:43.010 回答
7

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

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

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

于 2013-09-20T18:23:37.787 回答
6

这适用于管道以及输入文件:

seq 1 10 | perl -e'@x=<>;print@x[0..$#x-3]'
于 2013-09-20T18:23:39.940 回答
5

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

$ seq 10 | tac | sed '1,3d' | tac
1
2
3
4
5
6
7
于 2013-09-21T05:13:13.527 回答
2

怎么样 :

 seq 1 10 | perl -ne 'print if ( !eof  )' | perl -ne 'print if ( !eof  )' | perl -ne 'print if ( !eof  )' 
于 2013-09-20T18:08:02.313 回答
2

这个 awk 单线似乎可以完成这项工作:

awk '{a[NR%4]=$0}NR>3{print a[(NR-3)%4]}' file
于 2013-09-20T18:09:43.210 回答
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
于 2013-09-20T19:08:23.207 回答
1

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

这个解决方案是:

  • 纯粹的 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,我们可以从循环缓冲区中回显该行,然后将行 i 存储在循环缓冲区中。在读取前 n 行之前,不会回显任何内容。(i mod n) 是实现循环缓冲区的数组的索引。

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

于 2013-10-03T15:03:40.343 回答
0

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

awk 'BEGIN{X = 3; for(i = 0; i < X; ++i)getline a[i]}{i %= X; print a[i]; a[i++] = $0}'
于 2013-09-21T22:47:00.790 回答