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

Tyi*_*ilo 40 regex macos bash sed

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

此代码无效:

sed "s/\(1234\)/\n\1/g" input.txt > output.txt
Run Code Online (Sandbox Code Playgroud)

其中input.txt是:

test1234foo123bar1234
Run Code Online (Sandbox Code Playgroud)

和output.txt应该是:

test
1234foo123bar
1234
Run Code Online (Sandbox Code Playgroud)

但是我得到了这个:

testn1234foo123barn1234
Run Code Online (Sandbox Code Playgroud)

注意:

这个问题具体是关于"sed"的Mac OS X版本,社区已经注意到它的行为与Linux版本不同.

prz*_*moc 60

您的sed版本显然不支持\nRHS(替换的右侧).您应该阅读Eric Pement维护的SED常见问题解答,以选择一种可能的解决方案.我建议先尝试插入文字换行符.

以下是它的引用.


4.1.如何在替换的RHS中插入换行符?

几个版本的sed允许\n直接输入RHS,然后在输出上转换为换行符:ssed,gsed302a +,gsed103(带-x开关),sed15 +,sedmod和UnixDOS sed.最简单的解决方案是使用其中一个版本.

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

(a)如果从Bourne shell键入sed脚本,\如果脚本使用"单引号"或两个反斜杠(\\如果脚本需要"双引号"),则使用一个反斜杠.在下面的示例中,请注意>第2行的前导是由shell生成的,以提示用户输入更多内容.用户键入斜杠,单引号,然后按ENTER键终止命令:

 [sh-prompt]$ echo twolines | sed 's/two/& new\
 >/'
 two new
 lines
 [bash-prompt]$
Run Code Online (Sandbox Code Playgroud)

(b)在脚本中使用带有一个反斜杠的脚本文件\,紧接着是换行符.这将在"替换"部分嵌入换行符.例:

 sed -f newline.sed files

 # newline.sed
 s/twolines/two new\
 lines/g
Run Code Online (Sandbox Code Playgroud)

某些版本的sed可能不需要尾部反斜杠.如果是这样,请将其删除.

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

 echo twolines | sed 's/two/& new=/' | tr "=" "\n"   # produces
 two new
 lines
Run Code Online (Sandbox Code Playgroud)

(d)使用G命令:

G将换行符加上保留空间的内容添加到模式空间的末尾.如果保留空间为空,则无论如何都会附加换行符.换行符存储在模式空间\n中,可以通过分组处理\(...\)并在RHS中移动.因此,要更改前面使用的"twolines"示例,以下脚本将起作用:

 sed '/twolines/{G;s/\(two\)\(lines\)\(\n\)/\1\3\2/;}'
Run Code Online (Sandbox Code Playgroud)

(e)插入实线,而不是打破线条:

如果没有更改线条但只在模式之前或之后插入完整的线条,则程序更容易.使用i(insert)或a(append)命令,通过外部脚本进行更改.要This line is new在匹配正则表达式的每一行之前插入:

 /RE/i This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{x;s/$/This line is new/;G;}     # other seds
Run Code Online (Sandbox Code Playgroud)

上面的两个示例旨在作为从控制台输入的"单行"命令.如果使用sed脚本,则i\紧跟一个文字换行符将适用于所有版本的sed.此外,该命令s/$/This line is new/仅在保持空间已为空(默认情况下为空)时才起作用.

要在This line is new匹配正则表达式的每一行之后附加:

 /RE/a This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{G;s/$/This line is new/;}       # other seds
Run Code Online (Sandbox Code Playgroud)

在每行与正则表达式匹配后附加2个空行:

 /RE/{G;G;}                    # assumes the hold space is empty
Run Code Online (Sandbox Code Playgroud)

要将每个与正则表达式匹配的行替换为5个空行:

 /RE/{s/.*//;G;G;G;G;}         # assumes the hold space is empty
Run Code Online (Sandbox Code Playgroud)

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

在某些Unix版本的sed(不是GNU sed!)上,尽管该s///命令不会\n在RHS中接受,但该命令仍然y///可以.如果你的Unix sed支持它,aaa可以用这种方式插入一个换行符(不能移植到GNU sed或其他seds):

 s/aaa/&~/; y/~/\n/;    # assuming no other '~' is on the line!
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 20

这里有一个与之配合单行解决任何 POSIX兼容的sed(包括在Mac OS的FreeBSD版本),假设你的shell是bashkshzsh:

sed 's/\(1234\)/\'$'\n''\1/g' <<<'test1234foo123bar1234'
Run Code Online (Sandbox Code Playgroud)

请注意,您可以使用单个 ANSI C引用的字符串作为整个 sed脚本,sed $'...' <<<但这将需要\- 所有\实例(加倍),这非常麻烦并且妨碍可读性,如@tovk的回答所证明的那样.

  • $'\n'表示换行符并且是ANSI C引用的实例,它允许您使用控制字符转义序列创建字符串.
  • 上述拼接的ANSI C-引用字符串sed脚本如下:
    • 该脚本简单地分为2个单引号字符串,ANSI C引用的字符串卡在两半之间:
    • 's/\(1234\)/\'是上半部分 - 请注意它结束\,以便转义将作为下一个字符插入的换行符.(这种转义是将换行标记为替换字符串的一部分而不是被解释为命令的结尾所必需的).
    • $'\n'是换行符的ANSI C引用表示,在将脚本传递给shell 之前,shell会扩展为实际的换行符sed.
    • '\1/g' 是下半场.

请注意,此解决方案类似于其他控制字符,例如$'\t'表示制表符.


背景资料:

  • POSIX sed规范:http://man.cx/sed
    • BSD sed (也用于macOS)保持接近这个规范,而GNU sed提供了许多扩展.
  • 有关GNU sedBSD 之间差异的摘要,请sed访问/sf/answers/1699352931/

  • 这很棒,它还可以与Freebsd附带的sh一起使用 (2认同)
  • 为了在 OSX 上使用双引号进行这项工作,我这样做了:`sed "s/\(1234\)/\\"$'\n'"\1/g" &lt;&lt;&lt;'test1234foo123bar1234'` 有效意味着双-逃避`"`。 (2认同)

Phi*_*hil 8

Perl提供了更丰富的"扩展"正则表达式语法,在这里很有用:

perl -p -e 's/(?=1234)/\n/g'
Run Code Online (Sandbox Code Playgroud)

表示"在模式1234之后用换行替换零宽度匹配".这避免了必须使用反向引用捕获和重复部分表达式.


bmk*_*bmk 8

sed我的solaris版本可以说服这样工作(in bash):

echo test1234foo123bar1234 | sed 's/\(1234\)/\
\1/g'
Run Code Online (Sandbox Code Playgroud)

(你必须在反斜杠之后直接放置换行符).

csh我不得不再添加一个反斜杠:

echo test1234foo123bar1234 | sed 's/\(1234\)/\\
\1/g'
Run Code Online (Sandbox Code Playgroud)

sed简单使用的Gnu版本\n:

echo test1234foo123bar1234 | sed 's/\(1234\)/\n\1/g'
Run Code Online (Sandbox Code Playgroud)


oDD*_*ooL 5

获取GNU sed

$ brew install gnu-sed
Run Code Online (Sandbox Code Playgroud)

然后你的命令将按预期工作:

$ gsed "s/\(1234\)/\n\1/g" input.txt
test
1234foo123bar
1234
Run Code Online (Sandbox Code Playgroud)

注意:由于 mac 端口,您也可以获得 GNU sed。