2

suppose here is the file

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

Above is just an example but in real there are many columns and I need to replace column strings (e.g having heading name "def" to NA) where header matches. Expected output is

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

I am able to print only column where header name "def" with below command

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

But is there a way to print with modification and all the content of text file ONLY using AWK? Note: Its is not confirmed that always it will be 2nd column

0

3 Answers 3

8

Using Miller:

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

With -I, the changes are made "in-place", modifying the original file without outputting anything to the terminal.

5

Using any 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

The above assumes you WILL have a column name match, if you might not then add some defensive code like NR>1 && n { $n = "NA" }.

By the way, to print only the target column you'd change NR>1 { $n = "NA" } { print } to { print $n }, i.e. it'd be:

$ 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

The code in your question that you said was to print one column (I added some white space to make it easier to read):

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"" }
'

would actually be for printing multiple columns that each contain def in their name, not for printing one column that is named exactly def but better code for that would be:

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) }
'

because with THAT code you're using OFS rather than hard-coding the value " " you hope it will have, your array f[] starts at 1 instead of 0, like all generated awk arrays do and all manually created arrays should, and you don't need an additional print at the end to add the ORS.

0
-5
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
1
  • 3
    It seems to me that 1) If more than one column matches the def pattern (e.g. def1, def2 etc.), thiss will likely fail. 2) The output seems to remove the comma delimiters. 3) The two awk calls can be merged into a single call.
    – Kusalananda
    Sep 20, 2023 at 7:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .