如何在模式前面插入换行符?


138

如何在一行中的模式之前插入换行符?

例如,这将插入一个新行后面的正则表达式。

sed 's/regex/&\n/g'

如何在模式前面做同样的事情?

给定此样本输入文件,要匹配的模式是电话号码。

some text (012)345-6789

应该成为

some text
(012)345-6789

只需在此处使用sed重复如何在行后插入换行符/换行符的答案即可:sed '/regex/G'
Adam Schmideg,

1
@NilsvonBarth,为什么一个简单的问题是一个坏问题?
乔什

Answers:


177

可以在bashzsh上运行,并在Linux和OS X上进行了测试:

sed 's/regexp/\'$'\n/g'

通常,对于$单引号后面的字符串文字,请bash执行C样式的反斜杠替换,例如$'\t'转换为文字标签。另外,sed希望您的换行符用反斜杠转义,因此是\before $。最后,美元符号本身不应该用引号引起来,以便由外壳程序解释,因此我们在之前关闭引号$,然后再次将其打开。

编辑:如@ mklement0的注释中所建议,这也可以正常工作:

sed $'s/regexp/\\\n/g'

这里发生的是:整个sed命令现在是C样式的字符串,这意味着sed所需要的反斜杠必须放在换行文字之前,而现在应使用另一个反斜杠进行转义。尽管更具可读性,但是在这种情况下,您将无法执行shell字符串替换(而不必再次使其难看)。


7
这给了我OSX上“替代模式中的未转义换行符”。
马特·吉布森

@Matt Gibson这很奇怪,因为仅当您在替换模式中具有真正的换行符且没有反斜杠时才给出“未转义的换行符”。实际上,我上面的代码在其他shell中也有效,例如zsh,ksh。
mojuba

3
@Matt Gibson ...或者,如果您在我的代码中忘记了'$'\ n之前的反斜杠。
mojuba

7
如所写,这些表达式用换行符完全替换了正则表达式,而不是按要求在现有行的中间插入换行符。以下是我用这个答案的修改形式插入两个匹配的模式之间的换行:sed '\(first match\)\(second match\)/\1\'$'\n''\2/g'。请注意\ n后的两个单引号。第一个关闭“ $”部分,以便该行的其余部分不受此影响。没有这些引号,\ 2被忽略。
大卫·拉维蒂

12
另一个选择是使用单个 ANSI C引号的字符串sed $'s/regexp/\\\n/g',以提高可读性-唯一的警告是您需要将所有文字字符加倍\
mklement0

43

其他一些答案对我的sed版本不起作用。切换的位置&\n完成了工作。

sed 's/regexp/\n&/g' 

编辑:除非您安装,否则这似乎在OS X上不起作用gnu-sed


9
我不确定这是否适用于所有版本的sed。我想这对我的Mac和成\ n只是得到输出“N”
托德布林

3
在阅读您的答案之前,在Mac上花了15分钟在我的工作上。去苹果吧!
Rick77

1
对于那些使用自制软件的用户:brew install gnu-sed随后是gsed 's/regexp/\n&/g'
aaaaaa

1
...之后echo 'alias sed=gsed' >> ~/.bashrc
Proximo '18年

36

在sed中,您不能轻易在输出流中添加换行符。您需要使用一个续行,这很尴尬,但是可以使用:

$ sed 's/regexp/\
&/'

例:

$ echo foo | sed 's/.*/\
&/'

foo

有关详细信息,请参见此处。如果您想要一些不太尴尬的东西,可以尝试使用perl -pe匹配组而不是sed:

$ echo foo | perl -pe 's/(.*)/\n$1/'

foo

$1 指正则表达式中的第一个匹配组,其中组在括号中。


为什么说您不能添加换行符?您只需要sed's / regexp /&\ n / g'就可以了
Andres 2012年

2
这是您在Mac上可以插入换行符的外观最少的东西(\ n在Mac上不起作用)
Pylinux

可以修改perl版本以进行就地编辑perl -pi -e 's/(.*)/\n$1/' foo
同名,2015年

2
@Andres :(大多数)仅POSIX功能的Sed实现(例如OS X附带的BSD版本)在s函数调用的替换部分中不支持控制字符转义序列(与GNU Sed实现不同) 。上面的答案适用于两种实现方式;有关所有差异的概述,请参见此处
mklement0

29

在我的Mac上,以下代码插入一个'n'而不是换行符:

sed 's/regexp/\n&/g'

这将替换为换行符:

sed "s/regexp/\\`echo -e '\n\r'`/g"

我正在进行内联编辑,sed -i '' -e ...并且^M插入符号M(ctrl + m)被写入文件时遇到问题。我最终使用了具有相同参数的perl。
史蒂夫·陶伯

2
请注意第二个代码插入一个特殊的换行符代码LF CR(与MS-DOS CR LF相反)的事实!Unix操作系统和Mac OS X都仅使用LF(\n)。
pabouk

sed表达式中的其他内容引起了太多不满(尽管在没有echo...and和newline的情况下也可以正常工作),我只是在vim中这样做。
Ahmed Fasih 2014年

1
或简单地说:sed "s/regexp/`echo`/g"-这将产生单个LF而不是LF-CR
mojuba

2
@mojuba:否:`echo`将导致字符串,因为命令替换将始终修剪所有尾随的换行符。无法使用命令替换直接插入单个换行符(并且插入\n\r-即附加的CR-是一个糟糕的主意)。
mklement0

15
echo one,two,three | sed 's/,/\
/g'

1
+1运作完美,动作挺直/容易记住
-gMale

2
这个答案实际上是sed解决方案,而不是bash解决方案。任何使用类似结构的东西$'\n'都依赖于shell来生成换行符。这样的解决方案可能不是便携式的。这个是。当然,它也是tgamblin从2009
开始

10

在这种情况下,我不使用sed。我用tr。

cat Somefile |tr ',' '\012' 

这将使用逗号并将其替换为回车符。


1
我发现这也有效:cat Somefile | tr ',' '\n'YMMV
LS

9

您可以像使用sed一样使用perl单行代码,它具有完整的perl正则表达式支持(比sed强大得多)的优点。* nix平台之间的差异也很小-perl通常是perl。因此,您不必担心如何使特定系统的sed版本执行您想要的操作。

在这种情况下,您可以

perl -pe 's/(regex)/\n$1/'

-pe 将perl置于“执行和打印”循环中,非常类似于sed的正常操作模式。

' 引用其他所有内容,以便外壳不会干扰

()正则表达式周围是分组运算符。 $1替换的右侧会打印出这些括号中匹配的内容。

最后\n是换行符。

无论是否使用括号作为分组运算符,都必须转义要匹配的任何括号。因此,与您在上面列出的模式匹配的正则表达式将类似于

\(\d\d\d\)\d\d\d-\d\d\d\d

\(\)匹配文字括号,并\d匹配数字。

更好:

\(\d{3}\)\d{3}-\d{4}

我想您可以弄清楚括号中的数字在做什么。

另外,您可以对正则表达式使用/以外的定界符。因此,如果您需要匹配/您将不需要对其进行转义。下面的任何一个都相当于我回答开头的正则表达式。从理论上讲,您可以用 任何字符代替标准字符

perl -pe 's#(regex)#\n$1#'
perl -pe 's{(regex)}{\n$1}'

几个最后的想法。

使用-ne代替-pe行为类似,但不会在最后自动打印。如果您想自己打印,可以很方便。例如,这是一个类似grep的代码(m/foobar/是正则表达式匹配项):

perl -ne 'if (m/foobar/) {print}'

如果发现处理换行很麻烦,并且希望为您神奇地处理换行,请添加-l。不过,对于正在使用换行符的OP来说,它没有用。

额外提示-如果您安装了pcre软件包,则随附pcregrep,它使用完全兼容perl的正则表达式。


4

嗯,刚刚转义的换行符似乎可以在最新版本的sed(我有GNU sed 4.2.1)中工作,

dev:~/pg/services/places> echo 'foobar' | sed -r 's/(bar)/\n\1/;'
foo
bar

1
如前所述,这适用于各种版本的GNU sed,但不适用于macOS附带的sed。
LS 2016年

4
echo pattern | sed -E -e $'s/^(pattern)/\\\n\\1/'

在El Captitan的()支持下工作得很好


这非常有效,您甚至可以给出一个完整的命令来进行测试并从中推断出自己的专长。不错的工作!
jxramos

3

要在Linux上插入换行符以输出流,我使用了:

sed -i "s/def/abc\\\ndef/" file1

在哪里file1

def

在sed就地更换之前,并且:

abc
def

sed就位后更换。请注意的使用\\\n。如果图案"内部有图案,请使用进行转义\"


对我来说,上面的代码不起作用。sed插入\n而不是LF,因为它\\n从外壳程序获取参数。---此代码的工作:sed -i "s/def/abc\ndef/" file1。--- GNU sed version 4.2.1GNU bash, version 4.1.2(1) / 4.2.25(1)(CentOS版本6.4 / Ubuntu的12.04.3)。
pabouk

2

在sed中,您可以使用“ \ 1”,“ \ 2”,...来引用模式中的组。因此,如果要查找的模式是“ PATTERN”,并且您想在其前面插入“ BEFORE” ,可以使用,没有转义

sed 's/(PATTERN)/BEFORE\1/g'

  sed 's/\(PATTERN\)/BEFORE\1/g'

刚做过:testfile contents =“ ABC ABC ABC”。运行“ sed的s / \(ABC \)/ \ n \ 1 / g”测试文件,得到换行符。尝试进行转义,尝试一次将1件事添加到您的模式中,例如,确保匹配模式,然后检查组匹配,然后添加换行检查
Steve B.

我只是尝试了一下,然后得到了“ nABC nABC nABC”。您是否在使用其他版本的sed?
Todd Gamblin

外壳转义可能会妨碍tgamblin的尝试。将完整的sed参数放在单引号中,例如Steve B确实可以解决该问题。可能是因为不同版本的sed无法理解\ n换行符。
丹·普里兹

2

您还可以使用awk来执行此操作,使用-v提供的模式:

awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file

这将检查一行是否包含给定的模式。如果是这样,它将在其开头添加新行。

看一个基本的例子:

$ cat file
hello
this is some pattern and we are going ahead
bye!
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file
hello
this is some 
pattern and we are going ahead
bye!

注意它将影响一行中的所有模式:

$ cat file
this pattern is some pattern and we are going ahead
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' d
this 
pattern is some 
pattern and we are going ahead

1
1在此做什么?
whatahitson

1
@whatahitson 1在Awk中用作的简写{print $0}。原因是任何评估结果为True的条件都会触发Awk的默认操作,该操作包括打印当前记录。
fedorqui'SO停止伤害'18

1

这对我来说适用于MAC

sed -i.bak -e 's/regex/xregex/g' input.txt sed -i.bak -e 's/qregex/\'$'\nregex/g' input.txt

Dono是否完美的...


1

在阅读完该问题的所有答案之后,我仍然花了很多时间才能为以下示例脚本获取正确的语法:

#!/bin/bash
# script: add_domain
# using fixed values instead of command line parameters $1, $2
# to show typical variable values in this example
ipaddr="127.0.0.1"
domain="example.com"
# no need to escape $ipaddr and $domain values if we use separate quotes.
sudo sed -i '$a \\n'"$ipaddr www.$domain $domain" /etc/hosts

该脚本\n使用一个sed命令在文件末尾附加一个换行符和另一行文本。


1
sed -e 's/regexp/\0\n/g'

\ 0是空值,因此您的表达式将替换为空值(无),然后...
\ n是新行

在某些版本的Unix上不起作用,但我认为这是解决您的问题的方法。

echo "Hello" | sed -e 's/Hello/\0\ntmow/g'
Hello
tmow

0

在Red Hat上的vi中,我仅使用\ r字符即可插入回车符。我相信这是内部执行“ ex”而不是“ sed”的方法,但这是相似的,而vi可以是进行批量编辑(例如代码补丁)的另一种方法。例如。我用if语句围绕搜索词,该语句坚持在花括号后返回:

:.,$s/\(my_function(.*)\)/if(!skip_option){\r\t\1\r\t}/

请注意,我还让它插入了一些选项卡以使内容对齐更好。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.