我想模拟GNU的head -n -3
命令,它可以打印除了最后三行以外的所有行。因为FreeBSD上的head
命令没有这个功能。所以我考虑使用以下命令:
seq 1 10 | perl -ne ...
这里我使用了10行,但可以是任何大于3的数字。
在FreeBSD的BASH中,是否可以使用Perl或其他方式实现?
一个超级原始的解决方案是:
seq 1 10 | sed '$d' | sed '$d' | sed '$d'
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
seq 1 10 | perl -ne 'push @l, $_; print shift @l if @l > 3'
纯bash和简单工具(wc和cut):
head -n $(($(wc -l file | cut -c-8)-3)) file
这个可以通过管道或者输入文件来实现:
seq 1 10 | perl -e'@x=<>;print@x[0..$#x-3]'
@x
中,必须将整个内容保存在内存中。如果要寻找一个更简洁的解决方案,可以参考 @greg-bacon 的回复。 - LeoNerd似乎没有人使用 sed
和 tac
,那么这里就介绍一下:
$ seq 10 | tac | sed '1,3d' | tac
1
2
3
4
5
6
7
seq 1 10 | perl -ne 'print if ( !eof )' | perl -ne 'print if ( !eof )' | perl -ne 'print if ( !eof )'
eof
或 print
。 - mpapecawk '{a[NR%4]=$0}NR>3{print a[(NR-3)%4]}' file
这是一个晚回答,因为我昨天遇到了类似的问题。
这个解决方案具有以下特点:
已在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
$
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
另一种 Awk 解决方案,仅使用最少量的缓冲区,并快速打印行,无需先读取所有行。它还可以与管道和大文件一起使用。
awk 'BEGIN{X = 3; for(i = 0; i < X; ++i)getline a[i]}{i %= X; print a[i]; a[i++] = $0}'
-ne
和BEGIN{}
- mpapec