在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是bash
或ksh
或zsh
:
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'
来表示制表符。
背景信息 :
- POSIX
sed
规范: http : //man.cx/sed- BSD
sed
(也在OSX上使用)保持接近这个规格,而GNUsed
提供了许多扩展。
- BSD
- GNU
sed
和BSDsed
之间的区别总结可以在https://stackoverflow.com/a/24276470/45375find。;
我可以说服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兼容的sh
, printf
和sed
):
解决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