如何使用sed替换特定行位置的字符?

时间:2016-07-18 12:26:40

标签: bash awk sed

我正在尝试处理一些文件,我想将这些文件转换为.csv文件,因此我需要用逗号(',')替换一些特定字符(在我的情况下为空格)。 我相信这可以用sed或awk完成,但我没能写出正确的sed命令。

例如,输入文件如下所示(例如,只有两行)

 112 322432 434543    4555 3223
 adg gdasgg dagdag    gdag gdsg
 ...

请注意,输入文件中的数据不一定只用一个空格分隔,但保证输入文件对替换字符有效。 我需要替换每行第3,10,17,25列的每个字符。 相应的输出文件应该是这样的

 112,322432,434543,   4555,3223
 adg,gdasgg,dagdag,   gdag,gdsg
 ...

顺便说一句,是否可以编写一个sed脚本(而不是硬代码),我们可以定义一个包含我们需要用逗号替换空格的位置的数组。

===================

我的不好,取代连续的空格对我的情况不起作用。

abcde abcde abcde abcde abcde abcde abcde de bcde

以上几行显示我遇到的问题,一些数据字段可能为空,但不能忽略。幸运的是,输入文件保证所有数据字段都根据项目文档放置在正确的位置(给定每个字段的长度并且它们由单个空格分隔,尽管在输入文件中由于差异可能存在连续的空格在文件中所需的长度与实际的数据长度之间。)

6 个答案:

答案 0 :(得分:2)

sed -r 's/([^ ]) /\1,/g' File

查找匹配非空格字符后跟空格的字符串,然后替换为字符+ ,

答案 1 :(得分:1)

用于gensub()的GNU awk:

$ awk '{print gensub(/([^ ]) /,"\\1,","g")}' file
 112,322432,434543,   4555,3223
 adg,gdasgg,dagdag,   gdag,gdsg

$ awk -v pos='5 12 19 27' 'BEGIN{split(pos,a)} {for (i in a) $0=gensub(/./,",",a[i])} 1' file
 112,322432,434543,   4555,3223
 adg,gdasgg,dagdag,   gdag,gdsg

当你说要替换3号,10号,17号和25号位置的字符时,你的计数被2点关闭了:

$ awk -v pos='3 10 17 25' 'BEGIN{split(pos,a)} {for (i in a) $0=gensub(/./,",",a[i])} 1' file
 1,2 3224,2 4345,3    45,5 3223
 a,g gdas,g dagd,g    gd,g gdsg

答案 2 :(得分:1)

  

我需要替换每行第3,10,17,25列的每个字符。

我认为这意味着在空格分隔符之前或之后可能存在重要的空格字符,因此该行上的位置是识别字符到sub的唯一可靠方式。我还认为你实际上并不关心原始文件中那些位置的字符。如果你真的必须使用字符数来识别替换的位置,那么你可以这样做:

sed -e 's/\(.\{3\}\)./\1,/'  \
    -e 's/\(.\{10\}\)./\1,/' \
    -e 's/\(.\{17\}\)./\1,/' \
    -e 's/\(.\{25\}\)./\1,/' \
    input > output

每个片段在指定位置执行一次替换,方法是匹配所有字符,包括替换位置,并捕获替换位置之前的那些字符,并用捕获的字符和逗号替换它们。

或者,这相当于:

sed -e 's/\(.\{3\}\).\(.\{6\}\).\(.\{6\}\).\(.\{7\}\)./\1,\2,\3,\4,/' \
    input > output

答案 3 :(得分:1)

最简单的方法是使用awk方便的FIELDWIDTH变量指定列宽,使用-F删除空格分隔符,使用-v OFS=,将其替换为昏迷:

 awk -v FIELDWIDTHS="3 7 7 8 4" -F" " -v OFS=, '{print $1,$2,$3,$4,$5,$6}' file

返回:

 112,322432,434543,4555,3223,
 adg,gdasgg,dagdag,gdag,gdsg,

答案 4 :(得分:0)

只需将sequence of spaces替换为,

即可

sed的示例:

sed -r 's/ +/,/g' File

这将为您提供CSV输出。但这里的假设是数据本身没有任何空间。

答案 5 :(得分:0)

你可以这样做:

sed -r 's/(.{3})./\1,/; s/(.{10})./\1,/; ...'

换句话说,您将n个字符替换为另一个字符,原始的n字符后跟逗号。每个索引都需要这样的语句,这很不方便。但是,您也可以使用sed

自动执行此翻译
 echo 3 10 17 25 | sed 's/ /\n/g' | sed -r 's#(.*)#s/(.{\1})./\\1,/;#;' | sed -rf- input

您可以以稍微复杂的程序为代价取消sed的第一次调用:

echo 3 10 17 25 | sed -r 's#([^ ]+)( |$)#s/(.{\1})./\\1,/;\n#;P;D'  | sed -rf- input