41
awk '/^nameserver/ && !modif { printf("nameserver 127.0.0.1\n"); modif=1 } {print}' testfile.txt

It is displaying output but I want to write the output to same file. In my example testfile.txt.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
Venkat
  • 4,259
  • 4
  • 23
  • 20
  • 1
    possible duplicate of [awk save modifications inplace](http://stackoverflow.com/questions/16529716/awk-save-modifications-inplace) – kenorb May 20 '15 at 18:27

7 Answers7

65

Not possible per se. You need a second temporary file because you can't read and overwrite the same file. Something like:

awk '(PROGRAM)' testfile.txt > testfile.tmp && mv testfile.tmp testfile.txt

The mktemp program is useful for generating unique temporary file names.

There are some hacks for avoiding a temporary file, but they rely mostly on caching and read buffers and quickly get unstable for larger files.

thiton
  • 35,651
  • 4
  • 70
  • 100
19

Since GNU Awk 4.1.0, there is the "inplace" extension, so you can do:

$ gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' file1 file2 file3

To keep a backup copy of original files, try this:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") }
> { print }' file1 file2 file3

This can be used to simulate the GNU sed -i feature.

See: Enabling In-Place File Editing

kenorb
  • 155,785
  • 88
  • 678
  • 743
10

Despite the fact that using a temp file is correct, I don't like it because :

  • you have to be sure not to erase another temp file (yes you can use mktemp - it's a pretty usefull tool)

  • you have to take care of deleting it (or moving it like thiton said) INCLUDING when your script crash or stop before the end (so deleting temp files at the end of the script is not that wise)

  • it generate IO on disk (ok not that much but we can make it lighter)

So my method to avoid temp file is simple:

my_output="$(awk '(PROGRAM)' source_file)"
echo "$my_output" > source_file

Note the use of double quotes either when grabbing the output from the awk command AND when using echo (if you don't, you won't have newlines).

Sylock
  • 103
  • 1
  • 5
8

Had to make an account when seeing 'awk' and 'not possible' in one sentence. Here is an awk-only solution without creating a temporary file:

awk '{a[b++]=$0} END {for(c=1;c<=b;c++)print a[c]>ARGV[1]}' file
Hawk
  • 121
  • 1
  • 4
5

You can also use sponge from moreutils.

For example

awk '!a[$0]++' file|sponge file

removes duplicate lines and

 awk '{$2=10*$2}1' file|sponge file

multiplies the second column by 10.

Lri
  • 26,768
  • 8
  • 84
  • 82
1

Try to include statement in your awk file so that you can find the output in a new file. Here total is a calculated value.

print $total, total >> "new_file" 
Jérémie Bertrand
  • 3,025
  • 3
  • 44
  • 53
debi
  • 11
  • 1
0

This inline writing worked for me. Redirect the output from print back to the original file.

echo "1" > test.txt
awk '{$1++; print> "test.txt"}' test.txt
cat test.txt
#$> 2
lz100
  • 6,990
  • 6
  • 29