如何只替换文件中的特定列?

时间:2016-08-16 15:02:57

标签: regex bash sed

我正在处理名为test的长文件,如下所示:

AHAP   USA|NIS00333|+NULL|NISGOOGLE|NIS00005|*binary|NISCAR
KJJLIL123124%|NIS00160|+NULL|NISFACEBOOK|NIS00006|*binary|NISBUR
ASFASS9992|NIS00164|+NULL|NISTABLE|NIS00008|*binary|NISFANCY

我需要将字符串“NIS”替换为“NIX”,但是我只需要在由管道字符分隔的第二列中实现这一点,我的数据的分隔符是管道“|”,我有几列,总共七列,我只想在第二列中进行替换。

我试过了:

$ sed s/NIS/NIX/g test
AHAP   USA|NIX00333|+NULL|NIXGOOGLE|NIX00005|*binary|NIXCAR
KJJLIL123124%|NIX00160|+NULL|NIXFACEBOOK|NIX00006|*binary|NIXBUR
ASFASS9992|NIX00164|+NULL|NIXTABLE|NIX00008|*binary|NIXFANCY

但它影响了与字符串匹配的所有列:NIS并将其更改为NIX,我只想影响第二列,我想要的输出将是:

AHAP   USA|NIX00333|+NULL|NISGOOGLE|NIS00005|*binary|NISCAR
KJJLIL123124%|NIX00160|+NULL|NISFACEBOOK|NIS00006|*binary|NISBUR
ASFASS9992|NIX00164|+NULL|NISTABLE|NIS00008|*binary|NISFANCY

我非常感谢你对这个问题的帮助,谢谢你们。

2 个答案:

答案 0 :(得分:3)

如果您遇到列问题,请使用awk对其进行更好的原生控制:

$ awk 'BEGIN {FS=OFS="|"}{gsub("NIS","NIX",$2)}1' file
AHAP   USA|NIX00333|+NULL|NISGOOGLE|NIS00005|*binary|NISCAR
KJJLIL123124%|NIX00160|+NULL|NISFACEBOOK|NIS00006|*binary|NISBUR
ASFASS9992|NIX00164|+NULL|NISTABLE|NIS00008|*binary|NISFANCY

这会对基于2 nd |的字段执行gsub()替换。完成此替换后,1会触发awk的默认操作,包括打印$0,其中包含完整(已更新)的记录。

答案 1 :(得分:2)

sed解决方案:

$ sed 's/^\([^|]*|[^|]*\)NIS/\1NIX/' infile 
AHAP   USA|NIX00333|+NULL|NISGOOGLE|NIS00005|*binary|NISCAR
KJJLIL123124%|NIX00160|+NULL|NISFACEBOOK|NIS00006|*binary|NISBUR
ASFASS9992|NIX00164|+NULL|NISTABLE|NIS00008|*binary|NISFANCY

正则表达式,分手:

^          # Start of line anchor
\(         # Start of capture gruop
    [^|]*  # Characters other than pipe - first column
    |      # Column separator between first and second column
    [^|]*  # Characters other than pipe - first part of second column
\)         # End of capture group
NIS        # What we actually want to replace

这有一个限制,因为它只替换第二列中第一次出现的NIS。示例输入不再具有,但如果确实如此,我们可以使用条件分支来重复替换,只要它改变了模式空间:

sed '
:a
s/^\([^|]*|[^|]*\)NIS/\1NIX/
ta' infile

:a是要跳转到的标签,ta是条件分支命令(如果替换做了某事,“跳转到:a”。)

作为一个单行:

sed ':a;s/^\([^|]*|[^|]*\)NIS/\1NIX/;ta' infile

BSD sed(在Mac OS中找到)会抱怨标签没有被换行符,所以我们可以重写为

sed -e ':a' -e 's/^\([^|]*|[^|]*\)NIS/\1NIX/;ta' infile