一致する列で文字列を置き換える方法は?

一致する列で文字列を置き換える方法は?

これがファイルだと仮定

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だけを使用してテキストファイルのすべての内容を変更して印刷する方法はありますか?注:常に2番目の列であることは確認されていません。

答え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[]awk生成配列やすべての手動生成配列のように、配列は0ではなく1から始まるため、ORSでは必要ありません。print最後に追加してください。

答え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

関連情報