sed 或 awk 替换前 14 个匹配项

Posted

技术标签:

【中文标题】sed 或 awk 替换前 14 个匹配项【英文标题】:sed or awk replace first 14 ocurrences 【发布时间】:2014-11-02 22:34:57 【问题描述】:

我有一个由, 分隔的 csv 文件。不幸的是,最后一列是一个文本字段,一些字符串有逗号,所以当我尝试将 csv 导入 mysql 时,最后一列有时会被剪切。

我的 csv 文件示例(15 列) - 37k 行

Column1  ----------         Col2 Col3  Col4 ----      Col15   
server.domain.tld,IP,Country,City,(...),text random text, text text

我需要用; 替换除最后一个, 之外的所有内容,因此当我使用; 作为列分隔符将文件导入MySQL 时,字段15 不会被剪切。另一种方法是将前 14 个 ',' 替换为 ';'。

我需要的输出:

Column1  ----------         Col2 Col3  Col4 ----      Col15   
server.domain.tld;IP;Country;City;(...);text random text, text text

已经尝试过:

sed 's/,/;/g1-14'
sed 's/,/;/g1-14'
sed 's/,/;/g1,14'
sed 's/,/;/!14g'
sed 's/,/;/14g!'
sed 's/,/\1;\2;\3;\4;\5;\6;\7;\8;\9;\10;\11;\12;\13;\14;/'

【问题讨论】:

所以你不想替换最后一个逗号? 【参考方案1】:

您可以将它们全部替换为另一个字符,然后从位置 15 重置:

sed -e 's/,/;/g' -e 's/;/,/15g' file

看一个例子:

$ cat a
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$ sed -e 's/ /X/g' -e 's/X/ /15g' a
X1X2X3X4X5X6X7X8X9X10X11X12X13X14 15

想法基于Sed: Replace N first occurrences of a character。

【讨论】:

【参考方案2】:

下面的 Perl 命令会将所有逗号替换为 ;,除了最后一个。

perl -pe 's/,(?![^,]*$)/;/g' file

示例:

$ cat f
server.domain.tld,IP,Country,City,foo,bar,foo,bar,foobar,text random text, text text
$ perl -pe 's/,(?![^,]*$)/;/g' f
server.domain.tld;IP;Country;City;foo;bar;foo;bar;foobar;text random text, text text

【讨论】:

【参考方案3】:

这是另一个想法:引用最后一个字段:

sed -r 's/(([^,]*,)14)(.*)/\1"\3"/' <<END
f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,a,b,c,d
one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen
a,b,c,d,e,f,g,h,i,j,k,l,m,n
less,than,fourteen
END
f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,"a,b,c,d"
one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,"fifteen"
a,b,c,d,e,f,g,h,i,j,k,l,m,n
less,than,fourteen

【讨论】:

我认为 awk 可能更适合这个awk -F, '$NF="\""$NF"\""' OFS=, file 我不同意,你必须先找到前 N 个字段,然后剩下的就是最后一个字段,即使它包含逗号 很公平,不应该是14吗?【参考方案4】:

试试这个 sed 单线:

sed 's/,/;/g;s/;\([^;]*\)/,\1/'

一个小例子:

kent$  echo "foo,bar,foo,bar,foo,bar,here"|sed 's/,/;/g;s/;\([^;]*\)/,\1/'
foo;bar;foo;bar;foo;bar,here

我会添加一个带有s/.../.../ge 的gnu sed,虽然它比上面的行长一点

sed -r 's/(.*)(,.*)/echo $(echo \1|sed "s:,:;:g")\2/ge'

同样的例子:

kent$ echo "foo,bar,foo,bar,foo,bar,here"|sed -r 's/(.*)(,.*)/echo $(echo \1|sed "s:,:;:g")\2/ge'
foo;bar;foo;bar;foo;bar,here

【讨论】:

以上是关于sed 或 awk 替换前 14 个匹配项的主要内容,如果未能解决你的问题,请参考以下文章

sed / awk 匹配文件中第二次出现的正则表达式,并替换整行

Linux系列:grep过滤awk拆分sed替换的使用方法与区别

使用 sed/awk/grep 匹配段落并替换为新段落 [重复]

使用 sed/perl/awk 替换第一次出现的匹配文本

awk / sed:如果任何字段与模式匹配,则替换所有字段

如何使用 unix 实用程序 (sed/tr/awk) 用非转义等效项替换所有转义序列