使用sed将前两个空格替换为逗号

7

我有一个以空格分隔的文件,每行有不定数量的条目。我想要用逗号替换前两个空格,创建一个有三列的逗号分隔文件。

这是我的输入:

a b  1 2 3 3 2 1
c d  44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z y 2 3 33

以下是我期望的输出:

a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line,http://google.com,100 200 300
ef,jh,77 88 99
z,y,2 3 33

我正在尝试在sed命令中使用perl正则表达式,但是我无法完全让它工作。首先我尝试捕获一个单词,后跟一个空格,然后是另一个单词,但这只适用于第1、2和5行:

$ cat test | sed -r 's/(\w)\s+(\w)\s+/\1,\2,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z,y,2 3 33

我也尝试捕获空格、单词和更多的空格,但结果仍然相同:
$ cat test | sed -r 's/\s+(\w)\s+/,\1,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z,y,2 3 33

我也尝试使用 .? 通配符来做这件事,但是它对第四行代码做了一些奇怪的事情。
$ cat test | sed -r 's/\s+(.?)\s+/,\1,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh,,77 88 99
z,y,2 3 33

任何帮助都非常感激!
6个回答

9
这个怎么样:
sed -e 's/\s\+/,/' | sed -e 's/\s\+/,/'

这可能可以用一个sed命令实现,但这种方法确实很简单 :)
我的输出:
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line,http://google.com,100 200 300
ef,jh,77 88 99
z,y,2 3 33

谢谢,运行得非常好。我肯定是把它想复杂了! - Stephen Turner

4

试试这个:

sed -r 's/\s+(\S+)\s+/,\1,/'

我刚刚在你的尝试中,用\S+(一个或多个非空格字符)替换了\w(一个“单词”字符)。


3

只需提供多个-e参数,即可向单个sed实例提供多个命令。

要执行前两个命令,只需使用:

sed -e 's/\s\+/,/' -e 's/\s\+/,/'

这基本上是按顺序运行行中的两个命令,第一个处理第一块空格,第二个处理下一块。下面的记录展示了这个过程:
pax$ echo 'a b  1 2 3 3 2 1
c d  44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z y 2 3 33
' | sed -e 's/\s\+/,/' -e 's/\s\+/,/'

a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line,http://google.com,100 200 300
ef,jh,77 88 99
z,y,2 3 33

2

s///支持一种方法来指定要替换的模式的出现次数:只需在命令的末尾添加n即可只替换第n个出现的模式。因此,要替换第一个和第二个空格符,只需按照以下方式使用:

$ sed 's/  */,/1;s/  */,/2' input
a,b ,1 2 3 3 2 1
c,d ,44 55 66 2355
line,http://google.com 100,200 300
ef,jh ,77 88 99
z,y 2,3 33

编辑:阅读其他提出的解决方案,我注意到在s/ */,/后面的12不仅是不必要的,而且明显是错误的。默认情况下,s///只会替换第一次出现的模式。因此,如果我们有两个相同的s///连续出现,它们将替换第一次和第二次出现。你所需要的只是

$ sed 's/  */,/;s/  */,/' input 

请注意,如果您通过分号将两个sed命令分隔开,则可以在一个表达式中放置两个sed命令。一些sed实现不接受s///命令后的分号;在这种情况下,请使用换行符将命令分隔开。


1
一个 Perl 的解决方案是:
perl -pe '$_=join ",", split /\s+/, $_, 3' some.file

由于问题被标记为Perl和Sed标签,因此另一个Perl解决方案也无妨。perl -pe 's/([^\s,]+)\s/$1.(my$c++<3&& ",")." "/eg'实际上,我更喜欢同一线程中展示的join/split方法,但是稍加改动就可以得到s///eg的替代方法。该方法跟踪已执行的替换次数,并且每行仅在前三次进行逗号替换。也许将来会有/g{3}选项来限制m//g或s///g的匹配次数为三次。 - DavidO
如果使用Perl,至少要使用自动分割。;-) - Qtax
perl -anE 'say "$F[0],$F[1],$F[2] $F[3..$#F]"' - Qtax
我认为应该是 perl -anE 'say "$F[0],$F[1],$F[2] @F[3..$#F]"' - sid_com

0

不确定sed/perl,但这里有一个(丑陋的)awk解决方案。它只打印字段1-2,用逗号分隔,然后用空格分隔其余字段:

awk '{
  printf("%s,", $1)
  printf("%s,", $2)
  for (i=3; i<=NF; i++)
    printf("%s ", $i)
    printf("\n")
}' myfile.txt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接