OSX sed换行 - 为什么将空格转换为换行符,但换行符不会转换为空格

时间:2016-01-06 21:06:01

标签: macos sed

OSX上的sed有一些怪癖。此资源(http://nlfiedler.github.io/2010/12/05/newlines-in-sed-on-mac.html)包含有关如何将空格转换为换行符的信息:

 echo 'foo bar baz quux' | sed -e 's/ /\'$'\n/g'

或(@ ghoti的建议,使其更容易阅读):

echo 'foo bar baz quux' |  sed -e $'s/ /\\\n/g'

然而,当我尝试反向转换换行到空格时,它不起作用:

echo -e "foo\nbar" | sed -e 's/\'$'\n/ /g'

仅更改\n的更简单方法也不起作用:

echo -e "foo\nbar" | sed -e 's/\n/ /g'

这里有一个相关的答案:https://superuser.com/questions/307165/newlines-in-sed-on-mac-os-x,Spiff的详细答案(在页面末尾),但应用相同的逻辑并没有解决问题。

这是在OSX上运行的一种方式(通过http://www.benjiegillam.com/2011/09/using-sed-to-replace-newlines/):

 sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'

然而,我仍然很好奇为什么扭转原来的方法并不起作用。

更新:这里是如何让它使用两行(解决方案是使用N嵌入换行符):

echo -e "foo\nbar\n" | sed -e 'N;s/\n/ /g'

替代解决方案(详见@ghoti的完整答案):

echo -e "foo\nbar\n" | sed -n '1h;2,$H;${;x;s/\n/ /gp;}'

但是,这个解决方案似乎比问题陈述中建议的慢一点(注意这些命令的顺序很重要,因此尝试以不同的顺序测试它们可能是有意义的):

time seq 10000 | sed -n '1h;2,$H;${;x;s/\n/ /gp;}' > /dev/null

time seq 10000 | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' > /dev/null

3 个答案:

答案 0 :(得分:1)

sed的GNU手册页包括:

  

正常表达

     

应该支持POSIX.2 BRE,但由于性能问题,它们并不完全。正则表达式中的\n序列与换行符匹配,对\a\t和其他序列也是如此。

sed的Mac OS X手册页包括:

  

Sed正则表达式

     

默认情况下,sed中使用的正则表达式是基本正则表达式(BRE,有关详细信息,请参阅re_format(7)),但如果{{1}可以使用扩展(现代)正则表达式给出了标志。此外,-E对正则表达式添加了以下两个:

     
      
  1. 在上下文地址中,除反斜杠(sed)或换行符之外的任何字符都可用于分隔正则表达式。此外,在分隔字符前加上反斜杠字符会导致字符被字面处理。例如,在上下文地址\中,RE分隔符为\xabc\xdefx,第二个x代表自身,因此正则表达式为x

  2.   
  3. 转义序列abcxdef匹配嵌入在模式空间中的换行符。但是,您不能在地址或替换命令中使用文字换行符。

  4.   

这些不能说,但似乎是这种情况,在\n命令中,s/regex/new/部分是正则表达式,但是regex部分不是。在替换材料中,您必须使用new后跟换行符来嵌入换行符。在搜索材料(\)中,您可以使用regex

另请注意,\n适用于行。默认情况下,除了正则表达式元字符sed之外,模式空间末尾的换行几乎是无法匹配的。你不能通过匹配来删除该换行符。但是,您可以在模式空间中使用多行,然后可以使用$模式匹配嵌入的换行符。

答案 1 :(得分:1)

您的问题似乎是“为什么原始方法(将空格转换为换行符)的反转不起作用?”。

在sed中,换行符更多的是记录分隔符而不是行的一部分。考虑$,模式空间末尾的null,位于行的最后一个字符之后,并不是每行的换行符。

使用换行符的Sed命令,例如HN甚至s,在newline-as-record-separator的范围之外。您要替换的记录介于换行符之间。

为了替换换行符,您需要使用NH等将其置于模式空间中。

所以这是一个选择。

printf 'foo\nbar\nbaz\n' | sed -n '1h;2,$H;${;x;s/\n/ /gp;}'

我们的想法是,我们将所有行都附加到保持缓冲区,然后在文件末尾,将保持缓冲区移回模式空间进行替换,并一次性用空格替换换行符。 / p>

1h;2,$H构造避免了输出开头的空白,这是由在H的每一行数据之前附加的换行引起的。

答案 2 :(得分:0)

当我被OSX sed的特殊性所阻碍时,我倾向于依赖的几个替代方案是trperl

echo -e "foo\nbar" | tr '\n' ' '
foo bar

echo -e "foo\nbar" | perl -pe 's/\n/ /'
foo bar