如何替换匹配列中的字符串?

如何替换匹配列中的字符串?

假设这是文件

abc,def,ghi 
1,a,zeta
2,b,beta
3,c,ceta
4,d,xaq
5,gh,lpa

上面只是一个示例,但实际上有很多列,我需要替换标题匹配的列字符串(例如,将标题名称“def”更改为 NA)。预期输出是

abc,def,ghi 
1,NA,zeta
2,NA,beta
3,NA,ceta
4,NA,xaq
5,NA,lpa

我可以使用以下命令仅打印标题名称为“def”的列

awk -F, 'NR==1{for(i=1;i<=NF;i++)if($i~/def/)f[n++]=i}{for(i=0;i<n;i++)printf"%s%s",i?" ":"",$f[i];print""}' /tmp/test

但是有没有一种方法可以仅使用 AWK 进行修改并打印文本文件的所有内容?注意:尚未确认始终为第二列

答案1

使用Miller

$ mlr --csv put '$def = "NA"' file

使用-I,更改是“就地”进行的,修改原始文件而不向终端输出任何内容。

答案2

使用任何 awk:

$ awk -v col='def' '
    BEGIN { FS=OFS="," }
    NR==1 { for (n=1; n<=NF; n++) if ($n == col) break }
    NR>1  { $n = "NA" }
    { print }
' file
abc,def,ghi
1,NA,zeta
2,NA,beta
3,NA,ceta
4,NA,xaq
5,NA,lpa

上面假设您将有一个列名匹配,如果您可能没有,则添加一些防御代码,例如NR>1 && n { $n = "NA" }.

NR>1 { $n = "NA" } { print }顺便说一句,要仅打印您要更改为的目标列{ print $n },即:

$ awk -v col='def' -F, 'NR==1{for (n=1; n<=NF; n++) if ($n == col) break} {print $n}' file
def
a
b
c
d
gh

您所说的问题中的代码是打印一列(我添加了一些空格以使其更易于阅读):

awk -F, '
    NR==1 { for (i=1; i<=NF; i++) if ($i ~ /def/) f[n++]=i }
    { for (i=0; i<n; i++) printf "%s%s", i?" ":"", $f[i]; print"" }
'

实际上是为了打印多种的各列包含 def以他们的名字命名,而不是打印名为的一列确切地 def但更好的代码是:

awk -F, '
    NR==1 { for (i=1; i<=NF; i++) if ($i ~ /def/) f[++n]=i }
    { for (i=1; i<=n; i++) printf "%s%s", $(f[i]), (i<n ? OFS : ORS) }
'

" "因为使用该代码,您使用的是 OFS,而不是硬编码您希望它具有的值,您的数组f[]从 1 而不是 0 开始,就像所有生成的 awk 数组和所有手动创建的数组一样,并且您不需要print最后添加 ORS 。

答案3

col_num=$(awk -F "," '{for(i=1;i<=NF;i++){if ($i ~ /def/){print i }}}' content.txt)
awk -F "," -v col_num="$col_num"  'NR>1{$col_num="NA"}1' content.txt

output
abc,def,ghi
1 NA zeta
2 NA beta
3 NA ceta
4 NA xaq
5 NA lpa

相关内容