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

Nir*_*ngh 2 bash awk

假设这是文件

abc,def,ghi 
1,a,zeta
2,b,beta
3,c,ceta
4,d,xaq
5,gh,lpa
Run Code Online (Sandbox Code Playgroud)

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

abc,def,ghi 
1,NA,zeta
2,NA,beta
3,NA,ceta
4,NA,xaq
5,NA,lpa
Run Code Online (Sandbox Code Playgroud)

我可以使用以下命令仅打印标题名称“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
Run Code Online (Sandbox Code Playgroud)

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

Pra*_*ngh 8

使用Miller

$ mlr --csv put '$def = "NA"' file
Run Code Online (Sandbox Code Playgroud)

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


Ed *_*ton 5

使用任何 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
Run Code Online (Sandbox Code Playgroud)

上面假设您将有一个列名匹配,如果您可能没有,则添加一些防御代码,例如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
Run Code Online (Sandbox Code Playgroud)

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

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"" }
'
Run Code Online (Sandbox Code Playgroud)

实际上是用于打印名称中包含的列,而不是打印精确命名的一列,但更好的代码是: 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) }
'
Run Code Online (Sandbox Code Playgroud)

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