我试图用另一个分隔分割中的信息替换分隔分割中多次出现的模式。
我的分隔符是管道,在本例中,我想用第二列中的标签替换第三列中的每个匹配项。
所以如果我有一个包含内容的文件:
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'
但我不知道如何自动重复此操作,它只会替换第一次出现。
答案 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
进行处理或替换。