如何避免sed中的最后一个换行符?

如何避免sed中的最后一个换行符?,sed,Sed,我想删除文件的最后一部分,从遵循特定模式的一行开始,包括前面的换行符 因此,在“停止”处停止,以下文件: keep\n STOP\n whatever 应输出: keep 没有尾随的换行符 我试过了,逻辑似乎是可行的,但sed似乎每次打印缓冲区时都会添加一个换行符。我怎样才能避免呢?当sed不操作缓冲区时,我就没有这个问题(即如果我删除了STOP,sed在文件末尾输出“whatever”,而不使用换行符) 我正在尝试编写git清理过滤器,但我无法在每次提交时都追加新的换行符。使用awk,您可

我想删除文件的最后一部分,从遵循特定模式的一行开始,包括前面的换行符

因此,在“停止”处停止,以下文件:

keep\n
STOP\n
whatever
应输出:

keep
没有尾随的换行符

我试过了,逻辑似乎是可行的,但sed似乎每次打印缓冲区时都会添加一个换行符。我怎样才能避免呢?当sed不操作缓冲区时,我就没有这个问题(即如果我删除了STOP,sed在文件末尾输出“whatever”,而不使用换行符)

我正在尝试编写git清理过滤器,但我无法在每次提交时都追加新的换行符。

使用awk,您可以:

$ awk '$0=="STOP"{exit} {b=b (b==""?"":ORS) $0} END{printf "%s",b}' file
输出:

keep$
解释:

$ awk '                        
    $0=="STOP" { exit }        # exit at STOP, ie. go to END
    { b=b (b==""?"":ORS) $0 }  # gather an output buffer, control \n
    END { printf "%s",b }      # in the END output output buffer
' file    
。。。更多(稍微关注条件运算符):

这可能适用于您(GNU-sed):

-z
选项将整个文件拖到内存中,替换命令从第一个换行符中删除文件的其余部分,然后执行
停止

$ awk '/^STOP/{exit} {printf "%s%s", ors, $0; ors=RS}' file
keep$
上面打印的每一行都没有尾随的换行符,但是每第二行和后续的每一行前面都有一个换行符(
\n
\r\n
-根据您的环境要求,以便它在UNIX或Windows或其他任何环境下都能正常工作)。当它找到停止线时,它只是在打印任何内容之前退出

请注意,上面的代码除了当前行之外没有在内存中保留任何内容,因此无论输入文件有多大,也不管STOP出现在其中的什么位置,它都会工作-如果STOP是文件的第一行,它甚至会工作,这与到目前为止的其他答案不同


它还可以在每个UNIX设备的任何shell中使用任何awk。

Aww伙计,我刚刚花了一天时间学习sed多行语法,现在我必须学习awk了:你能把第二行再细分一下吗?我知道b是一个变量,所谓的缓冲区,我读到ORS是新行,我知道$0是管道中的当前行,而==是一个测试。但我没能把这些元素放在一起。。。(我是一个Windows PowerShell的家伙。)生活不是很美好吗,每天学习更多吗我马上就把这句话说清楚。太棒了,谢谢。如果有人通过搜索sed替换,我只想补充一点,第一个条件可以用regexp替换:$0~'STOP.*'@XavierPlantefève sed用于在单个行上执行s/old/new,仅此而已。对于任何其他方面,您都应该使用awk来实现可移植性、清晰性、健壮性、效率以及软件中的所有其他重要功能。40年前,当awk发明时,所有用于做其他事情的sed结构实际上都已经过时了,直到今天仍然存在,只是为了进行思维训练——你实际上并没有在生产软件中使用它们。Holly Molly,它是有效的。我在Windows上使用git,因此它包括Cygwin,Cygwin使用GNU版本的实用程序。在经历了所有的尝试和错误之后,这几乎太简单了。除了对sed内部的解释之外,这就是我需要的答案。谢谢。@XavierPlantefève您确实明白,当您移动到另一个未使用GNU的平台时,它会失败,如果您有一个很大的文件,它会失败,因为它会一次性将整个文件读入内存,并且比发布的awk脚本慢得多。您可以用GNU awk(
awk-v RS='^$'{sub(/\nSTOP.*/,“”)}1'
)编写几乎完全相同的脚本,但您不会,因为有更健壮、可移植、高效的方法来完成这项工作。我完全理解,但在这种情况下,测试平台是非常可控的:它用于Windows上的git过滤器,那最多只能收到几百行。由于服务结构的原因,范围纯粹是Windows。更重要的是,未来的管理员越容易理解它,它就越好。这个问题是关于sed的,这让我选择了这个答案。请放心,我把你的答案作为个人成长的书签,以供将来的项目参考。哦,是的,非常简洁。哦,是不是因为ors是小写的,是一个变量,因此在第一个循环结束时才是空的?是的。这是为第二行和后续行打印内容的非常常见的方法之一。我必须承认我非常喜欢它。好的,我将继续使用sed解决方案,因为它更适合我的情况,但我将此作为一个答案,因为它可以使其他人受益。
    b=b             # appending to b, so b is b and ...
    (b==""?"":ORS)  # if b was empty, add nothing to it, if not add ORS ie. \n ...
    $0              # and the current record
sed -z 's/\nSTOP.*//' file
$ awk '/^STOP/{exit} {printf "%s%s", ors, $0; ors=RS}' file
keep$