有一个像foo.txt这样的包含内容的文件
1
2
3
4
5假设行数可以是不同的,我如何获得其中以4和5开头的行(最后一个空行之后的所有行)?
发布于 2019-01-25 04:04:59
已更新
让我们仅用sed来尝试一种稍微简单一点的方法。
$: sed -n '/^$/{g;D;}; N; $p;' foo.txt
4
5-n说除非我告诉你否则不要打印。
/^$/{g;D;};在每个空白行上说,用以下命令清除所有内容:
g:将模式空间的内容替换为保留空间的内容。由于我们从未放入任何内容,这将擦除(可能是长期累积的)模式空间。请注意,我本可以使用z,因为这是GNU,但我想在下面的非GNU模式中使用它,在这种情况下,这适用于both.D:从模式空间中删除现在为空的行,然后阅读下一行。现在,如果(且仅当)我们看到空行,则先前累积的行将被擦除。D循环回到开头,因此N永远不会看到空行。
N:在模式空间中添加一个换行符,然后将下一行输入附加到模式空间。在除空格之外的每一行上都会执行此操作,否则模式空间将为空。这将累积所有非空格,直到1)命中空格,这将如上所述清除并重新启动缓冲区,或者2)我们到达EOF时缓冲区完好无损。
最后,$p在最后一行上说(除非最后一行是空的,否则已经添加到模式空间中,这将删除模式空间...),打印模式空间。只有当文件的最后一行是空行时,才不会打印任何内容。
因此,整个逻辑可以归结为:在空行上清除缓冲区,否则将非空行堆叠在一起并在末尾打印。
如果您没有GNU sed,只需将命令放在单独的行上即可。
sed -n '
/^$/{
g
D
}
N
$p
' foo.txt替代方案
上面的方法是有效的,但可能会在某些数据集上建立非常大的模式缓冲区。如果这不是问题,那就去做吧。
或者,如果你想在简单的步骤中完成它,不要介意更多的进程做更少的工作,而更喜欢消耗更少的内存:
last=$( sed -n /^$/= foo.txt|tail -1 ) # find the last blank
next=$(( ${last:-0} + 1 )) # get the number of the line after
cmd="$next,\$p" # compose the range command to print
sed -n "$cmd" foo.txt # run it to print the range you wanted它在sed之外运行了许多小而简单的任务,因此它可以为sed提供对任务最简单、最直接和最有效的描述。它将读取目标文件两次,但不必管理填充、刷新和重新填充模式缓冲区中积累的数据,并在空白行之前添加记录。我认为,除非你是内存受限的,否则仍然可能更慢。
发布于 2019-01-25 03:45:06
反转文件,打印直到第一个空行的所有内容,再反转一次。
$ tac foo.txt | awk '/^$/{exit}1' | tac
4
5发布于 2019-01-25 22:32:40
使用GNU awk
awk -v RS='\n\n' 'END{printf "%s",$0}' fileRS是设置为空行的记录分隔符。
END语句打印最后一条记录。
https://stackoverflow.com/questions/54352272
复制相似问题