在sed中插入换行(Mac OS X)

如何在sed的replace部分插入换行符?

此代码不起作用:

sed "s/\(1234\)/\n\1/g" input.txt > output.txt 

其中input.txt是:

 test1234foo123bar1234 

和output.txt应该是:

 test 1234foo123bar 1234 

但是我感到这个:

 testn1234foo123barn1234 

注意:

这个问题特别是关于“sed”的Mac OS X版本,社区已经注意到它的行为与Linux版本不同。

您的sed版本显然不支持\n在RHS(替代的右侧)。 您应该阅读由Eric Pement维护的SED FAQ ,以select可能的解决scheme之一。 我build议先尝试插入文字换行符。

下面是它的引用。


4.1。 我如何在换人的RHS中插入换行符?

几个版本的sed允许直接input到RHS中,然后在输出上将其转换为换行符:ssed,gsed302a +,gsed103(带有-x开关),sed15 +,sedmod和UnixDOS sed。 最简单的解决scheme是使用这些版本之一。

对于其他版本的sed,请尝试以下操作之一:

(a)如果从Bourne shellinputsed脚本,如果脚本使用“单引号”或两个反斜杠,如果脚本需要“双引号”,则使用一个反斜杠\ 。 在下面的例子中,请注意shell的第二行上的leading >会提示用户input更多的信息。 用户input斜线,单引号,然后按ENTER来终止命令:

  [sh-prompt]$ echo twolines | sed 's/two/& new\ >/' two new lines [bash-prompt]$ 

(b)在脚本中使用带有一个反斜杠\的脚本文件,之后紧跟一个换行符。 这将在“replace”部分embedded一个换行符。 例:

  sed -f newline.sed files # newline.sed s/twolines/two new\ lines/g 

有些版本的sed可能不需要尾随的反斜杠。 如果是这样,删除它。

(c)插入一个未使用的字符并通过trpipe道输出:

  echo twolines | sed 's/two/& new=/' | tr "=" "\n" # produces two new lines 

(d)使用G命令:

G追加一个换行符,加上保留空间的内容到模式空间的末尾。 如果保留空间是空的,则总是附加一个换行符。 换行符存储在模式空间中, \n可以通过将\(...\)分组并在RHS中移动来处理。 因此,要改变之前使用的“twolines”示例,以下脚本将起作用:

  sed '/twolines/{G;s/\(two\)\(lines\)\(\n\)/\1\3\2/;}' 

(e)插入整行,而不是划线:

如果不改变线条,只在模式之前或之后插入完整的线条,则该过程要容易得多。 使用i (插入)或(append)命令,通过外部脚本进行更改。 要插入This line is new每一行匹配一个正则expression式:

  /RE/i This line is new # HHsed, sedmod, gsed 3.02a /RE/{x;s/$/This line is new/;G;} # other seds 

上面的两个例子是作为从控制台input的“单行”命令的。 如果使用sed脚本, i\立即紧接着一个字面换行符将在所有版本的sed上工作。 此外,命令s/$/This line is new/只有当保持空间已经是空的(默认情况下)才有效。

追加This line is new每行匹配正则expression式后This line is new

  /RE/a This line is new # HHsed, sedmod, gsed 3.02a /RE/{G;s/$/This line is new/;} # other seds 

在每行匹配正则expression式后追加2个空行:

  /RE/{G;G;} # assumes the hold space is empty 

用5个空行replace每行匹配正则expression式:

  /RE/{s/.*//;G;G;G;G;} # assumes the hold space is empty 

(f)如果可能,使用y///命令:

在sed的一些Unix版本上(不是GNU sed!),虽然s///命令不会接受RHS中的\n ,但是y///命令却可以。 如果你的Unix sed支持它, aaa之后的换行符可以这样插入(这对GNU sed或其他seds是不可移植的):

  s/aaa/&~/; y/~/\n/; # assuming no other '~' is on the line! 

这是一个单线解决scheme,可以与POSIX兼容的sed (包括OSX上的FreeBSD版本)一起工作, 假设你的shell是bashkshzsh

 sed 's/\(1234\)/\'$'\n''\1/g' <<<'test1234foo123bar1234' 

请注意,你可以使用一个ANSI C引用的string作为整个 sed脚本sed $'...' <<< ,但是这将需要\转义所有的\实例(加倍),这是相当繁琐和阻碍可读性,由@ tovk的答案certificate)。

  • $'\n'表示换行符,是ANSI C引用的一个实例,它允许您使用控制字符转义序列创buildstring。
  • 上面将ANSI C引用的string拼接 sed脚本中 ,如下所示:
    • 脚本简单地分成两个单引号string,ANSI C引号string在两半之间
    • 's/\(1234\)/\'是上半部分 – 注意它\结尾,以便转义将作为下一个字符插入的换行符。 (为了将换行符标记为replacestring的一部分,而不是将其解释为命令的结尾,这个转义是必要的。
    • $'\n'是一个换行符的ANSI C引用表示, 在将脚本传递给sed之前,shell将其扩展为实际的换行符
    • '\1/g'是下半场。

请注意,此解决scheme类似于其他控制字符 ,如$'\t'来表示制表符。


背景信息

我可以说服sed的solaris版本以这种方式工作(在bash ):

 echo test1234foo123bar1234 | sed 's/\(1234\)/\ \1/g' 

(你必须在反斜杠之后直接放行)。

csh我必须csh一个反斜杠:

 echo test1234foo123bar1234 | sed 's/\(1234\)/\\ \1/g' 

sed的GNU版本只是使用\n

 echo test1234foo123bar1234 | sed 's/\(1234\)/\n\1/g' 

Perl提供了一个更丰富的“扩展”正则expression式语法,这在这里很有用:

 perl -p -e 's/(?=1234)/\n/g' 

意思是“用一个换行符替代模式1234之后的零宽度匹配”。 这避免了必须捕捉和重复部分expression的反向引用。

不幸的是,对我而言, sed似乎忽略了replacestring中的\n s。

 $ echo test1234foo123bar1234 | sed "s/\(1234\)/\n\1/g" testn1234foo123barn1234 

如果这也发生在你身上,另一种方法是使用:

 $ echo test1234foo123bar1234 | sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g" 

这应该在任何地方工作,并会产生:

 test 1234foo123bar 1234 

对于以input.txt文件作为input, output.txt作为输出的示例,请使用:

 $ sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g" input.txt > output.txt 

得到一个GNU sed 。

 $ brew install gnu-sed 

那么你的命令将按预期工作:

 $ gsed "s/\(1234\)/\n\1/g" input.txt test 1234foo123bar 1234 

NB:您也可以通过Mac端口获得GNU sed。

尝试这个:

 $ echo test1234foo123bar1234 | sed "s/\(1234\)/\n\1/g" test 1234foo123bar 1234 

从Sed Gnu doc

 g Apply the replacement to all matches to the regexp, not just the first. 

你也可以使用Bash的$'string'特性:

 man bash | less -p "\\$'" printf '%s' 'test1234foo123bar1234' | sed $'s/\\(1234\\)/\\\n\\1/g' 

在命令中间的换行符会感觉有点笨拙:

 $ echo abc | sed 's/b/\ /' a c 

下面是这个问题的两个解决scheme,我认为这应该是相当便于使用的(应该​​适用于任何POSIX兼容的shprintfsed ):

解决scheme1:

请记住在这里转义printf \%字符:

 $ echo abc | sed "$(printf 's/b/\\\n/')" a c 

为了避免需要printf \%字符:

 $ echo abc | sed "$(printf '%s\n%s' 's/b/\' '/')" a c 

解决scheme2:

创build一个包含这样一个换行符的variables:

 newline="$(printf '\nx')"; newline="${newline%x}" 

或者像这样:

 newline=' ' 

然后像这样使用它:

 $ echo abc | sed "s/b/\\${newline}/" a c