Reputation: 653
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
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
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
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
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
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