awk 命令打印除最后三行之外的所有行

Avi*_*Raj 8 command-line awk

我只想通过 awk 打印输入中除最后三行之外的所有行。请注意,我的文件包含 n 行。

例如,

file.txt 包含,

foo
bar
foobar
barfoo
last
line
Run Code Online (Sandbox Code Playgroud)

我希望输出是,

foo
bar
foobar
Run Code Online (Sandbox Code Playgroud)

我知道通过tacsedtac和的组合是可能的awk

$ tac file | sed '1,3d' | tac
foo
bar
foobar

$ tac file | awk 'NR==1{next}NR==2{next}NR==3{next}1' | tac
foo
bar
foobar
Run Code Online (Sandbox Code Playgroud)

但我只希望通过 awk 输出。

Oli*_*Oli 16

它非常笨重,但您可以将每一行添加到数组中,并在最后——当你知道长度时——输出除最后 3 行之外的所有内容。

... | awk '{l[NR] = $0} END {for (i=1; i<=NR-3; i++) print l[i]}'
Run Code Online (Sandbox Code Playgroud)

另一种(这里更有效)方法是手动堆叠三个变量:

... | awk '{if (a) print a; a=b; b=c; c=$0}'
Run Code Online (Sandbox Code Playgroud)

a仅在一行从cto移动到b然后进入后打印,a因此将其限制为三行。直接的好处是它不会将所有内容存储在内存中,并且它不应该导致缓冲问题(fflush()如果有的话在打印之后),但这里的缺点是扩展它并不简单。如果要跳过最后 100 行,则需要 100 个变量和 100 个变量杂耍。

如果 awk 有数组的pushpop运算符,那就更容易了。

或者我们可以预先计算行数以及我们实际想要走多远$(($(wc -l < file) - 3))。这对于流式内容相对没用,但在文件上,效果很好:

awk -v n=$(($(wc -l < file) - 3)) 'NR<n' file
Run Code Online (Sandbox Code Playgroud)

通常来说,您只会使用head

$ seq 6 | head -n-3
1
2
3
Run Code Online (Sandbox Code Playgroud)

使用terdon 的基准,我们实际上可以看到这些比较。我想我会提供一个完整的比较:

  • head: 0.018s (我)
  • awk+ wc: 0.169s (我)
  • awk 3个变量:0.178s(我)
  • awk 双文件:0.322s(terdon)
  • awk 循环缓冲区:0.355s(Scrutinizer)
  • awk for循环:0.693s(我)

最快的解决方案是使用 C 优化的实用程序,例如headwc处理繁重的事情,但在纯粹的情况下 awk,手动旋转堆栈目前是王道。

  • +1,`head` 是最好的选择。 (4认同)
  • 是的,它是一个 GNU 扩展。但是,这是 Ask *Ubuntu*,所以我认为这不是问题...... (3认同)
  • @glennjackman,但 OP 只要求“awk”。此外,与 `-n-3` 一起使用的 `head` 是一个 GNU 扩展并且没有被 POSIX 指定。 (2认同)

Scr*_*zer 6

为了尽量减少内存使用,您可以使用循环缓冲区:

awk 'NR>n{print A[NR%n]} {A[NR%n]=$0}' n=3 file
Run Code Online (Sandbox Code Playgroud)

通过在行号上使用 mod 运算符,我们最多有 n 个数组条目。

以n=3为例:

第 1 行NR%n等于 1,第 2 行产生 2,第 3 行产生 0,第 4 行再次计算为 1。

Line 1 -> A[1]
Line 2 -> A[2]
Line 3 -> A[0]
Line 4 -> A[1]
Line 5 -> A[2]
...
Run Code Online (Sandbox Code Playgroud)

当我们到达第 4 行时,A[NR%n]包含第 1 行的内容。因此,打印出来并A[NR%n]获取第 4 行的内容。下一行(第 5 行)打印第 2 行的原始内容,依此类推,直到我们到达结尾。未打印的是缓冲区的内容,其中包含最后 3 行...