Shuvo Shams
Shuvo Shams

Reputation: 653

AWK: replace and write a column value in the input file

I am trying to replace the $3 column values of the input file if $3 is > 100. I tried:

awk 'BEGIN {FS="\t"} {if($3 > 100) $3=$3/100;print}' test.stat

This outputs the correct changes to the stdout, but I need the change to be written to the input file (test.stat) such that the values of the remaining fields/records remain unchanged. Any suggestion?

Upvotes: 14

Views: 36129

Answers (5)

tripleee
tripleee

Reputation: 189397

If you have GNU Awk, it has an -i inplace option which works similarly to the (nonstandard but common) -i option of sed. In other words, it will write the changes back to the original file (probably using a temporary file behind the scenes).

awk -i inplace 'BEGIN {FS="\t"}
  {if($3 > 100) $3=$3/100;print}' test.stat

Tangentially, you might want to preserve the tabs on output, and simplify the syntax slightly.

awk -i inplace 'BEGIN {FS=OFS="\t"}
  ($3 > 100) { $3=$3/100 } 1' test.stat

where OFS=FS="\t" sets both the input and the output field separators to a tab, and we use the common 1 idiom to print all input lines.

If you don't have GNU Awk, you will probably get something like

awk: unknown option -i ignored

and if you want to check which Awk you have, awk --version should print something like

GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
Copyright (C) 1989, 1991-2020 Free Software Foundation.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.

Just to spell this out, there are multiple common versions of Awk. Brian Kernighan's "new Awk" (which was "new" in 1993 and is a direct descendant of the original Bell Labs Awk) is sometimes called nawk, and there is a version called "Mike's Awk" which is often available as mawk. GNU Awk is sometimes installed as gawk, or from a package with that name. There are multiple other implementations, including of course a separate one for Busybox.

On Debian-like platforms, update-alternatives will let you select which Awk version from the installed ones you want to use when you type just awk.

Of course, the common and standard portable solution is to write the results to a new file and then move it on top of the original, as already suggested in multiple answers.

Upvotes: 0

Andrew Beals
Andrew Beals

Reputation: 1187

Awk isn't designed to edit things in-place. It's designed to process data and write it to stdout (or another file). You can do something like this:

$ awk 'BEGIN {FS="\t"} {if($3 > 100) $3=$3/100;print}' test.stat > test.stat.new \
    && mv test.stat test.stat.old && mv test.stat.new test.stat

Upvotes: 12

Kent
Kent

Reputation: 195059

awk 'BEGIN {FS="\t"} {if($3 > 100) $3=$3/100;print}' test.stat > /tmp/tmp.stat && mv /tmp/tmp.stat test.stat

this should work

Upvotes: 4

glenn jackman
glenn jackman

Reputation: 246807

To make your command more awk-like:

awk -F '\t' '$3 > 100 {$3 = $3/100} {print}' test.stat

To overwrite the file, you need to write to a temp file

f=$(mktemp)
cp test.stat test.stat.bak$(date +%s)  ;# if you want a backup copy
awk '...' test.stat > "$f" && mv "$f" test.stat

Upvotes: 2

Eduardo Ivanec
Eduardo Ivanec

Reputation: 11862

As far as I know awk doesn't have in-place editing as sed does (via the -i switch).

The easy solution, of course, is to use a temp file and overwrite the original file afterwards. This is the solution recommended even in comp.lang.awk.

The harder solution is to save the changes to an awk array and add an END block that dumps the contents of the array to the original file.

Upvotes: 3

Related Questions