替换分隔列中的多个出现

时间:2017-03-19 12:24:51

标签: bash sed

我试图用另一个分隔分割中的信息替换分隔分割中多次出现的模式。

我的分隔符是管道,在本例中,我想用第二列中的标签替换第三列中的每个匹配项。

所以如果我有一个包含内容的文件:

33|29|aa aa aa aa aa
28|12|aa aa aa aa aa
11|12|aa aa aa aa aa aa aa aa aa
9|9|aa aa aa aa

我希望输出为:

33|29|29 29 29 29 29
28|12|12 12 12 12 12
11|12|12 12 12 12 12 12 12 12 12
9|9|9 9 9 9

我所想到的是使用带有这样的后引用的sed:

sed 's/|\([0-9][0-9]*\)|\(aa *\)/|\1|\1 /g'

但我不知道如何自动重复此操作,它只会替换第一次出现。

5 个答案:

答案 0 :(得分:4)

使用sed,假设第二列始终由[0-9]个字符组成,第三列不包含数字

$ sed -E ':a s/^([^|]+\|)([^|]+)(\|[0-9 ]*)[^0-9 ]+/\1\2\3\2/; ta' ip.txt 
33|29|29 29 29 29 29
28|12|12 12 12 12 12
11|12|12 12 12 12 12 12 12 12 12
9|9|9 9 9 9
  • :a标签a
  • ^([^|]+\|)第一栏和|
  • ([^|]+)第二列值
  • (\|[0-9 ]*)保存|以及任何数字和空格序列
    • 在第一次迭代中仅匹配|
    • |并在第二次迭代中首先替换值和空格,依此类推
  • [^0-9 ]+要替换的字符
  • 只要有匹配
  • ta分支到a标签

后来意识到可以减少反向引用的数量:

sed -E ':a s/^([^|]+\|([^|]+)\|[0-9 ]*)[^0-9 ]+/\1\2/; ta' ip.txt


awk。感谢@EdMorton的建议

$ awk 'BEGIN{FS=OFS="|"} {gsub(/[^ ]+/, $2, $3)} 1' ip.txt 
33|29|29 29 29 29 29
28|12|12 12 12 12 12
11|12|12 12 12 12 12 12 12 12 12
9|9|9 9 9 9
  • BEGIN{FS=OFS="|"}将输入/输出字段分隔符设置为|
  • gsub("[^ ]+", $2, $3)替换值为$2的所有非空格字符序列。仅在第三栏
  • 上执行此操作
  • 1以惯用方式打印每一行
  • 假设第二列不包含&,因为它是替换部分中的特殊字符。请参阅gawk manual

答案 1 :(得分:2)

Perl解决方案:

perl -F'\|' -lanE 'print join("|",@F[0,1],$F[2]=~s/\b(\S+)\b/$F[1]/gr)' file

输出

33|29|29 29 29 29 29
28|12|12 12 12 12 12
11|12|12 12 12 12 12 12 12 12 12
9|9|9 9 9 9

需要perl -v v5.14或更高版本。或

perl -F'\|' -lanE 'print join("|",@F[0,1],map{s/\b(\S+)\b/$F[1]/g;$_}$F[2])'

任何perl版本。

编辑: 非常好 @Sundeep的解决方案

perl -F'\|' -ape 's/.*\|\K.*/$&=~s|[^ ]+|$F[1]|gr/e'

答案 2 :(得分:1)

你想要像

这样的命令
sed 's/.*|\([0-9][0-9]*\)|.*/\/\1\/s#aa#\1#g/' inputfile

两次使用sed

sed -f <(sed 's/.*|\([0-9][0-9]*\)|.*/\/\1\/s#aa#\1#g/' inputfile) inputfile

编辑: 以及..|1234|....|123|..等重叠键如何? 使用@potong在他/她的评论中提出的改进。

答案 3 :(得分:0)

awk将是我的选择,因为它涉及列:

awk -F'|' 'gsub(/aa/,$2)' file

如果其他列(由管道分隔)中的数据可能无法更改,则只需在gsub调用中包含$ 3.

正如我最近才知道的那样,如果您希望按原样编辑并使用gawk,您还可以包含'-i inplace',并且数据将会为您更改。

答案 4 :(得分:0)

awk '{split($1,a,"|");gsub(a[3],a[2])}1' fil
33|29|29 29 29 29 29
28|12|12 12 12 12 12
11|12|12 12 12 12 12 12 12 12 12
9|9|9 9 9 9

此处,使用split函数将第一列划分为块,然后gsub进行处理或替换。