Gawk inplace and stdout

awkgawk

Is it possible to use gawk's -i inplace option and also print things to stdout?

For example, if I wanted to update a file, and if there are any changes print the name of the file and the changed lines to stderr I could do something like

find -type f -name 'myfiles' -exec gawk -i inplace '{if(gsub(/pat/, "repl")) { print FILENAME > "/proc/self/fd/2" ; print > "/proc/self/fd/2"; } print;}' {} +

but is there a way to use stdout instead, or a cleaner way to print that block to the alternate stream?

Best Answer

You should use /dev/stderr or /dev/fd/2 instead of /proc/self/fd/2. gawk handles /dev/fd/x and /dev/stderr by itself (regardless of whether the system has those files or not).

When you do a:

print "x" > "/dev/fd/2"

gawk does a write(2, "x\n"), while when you do:

print "x" > "/proc/self/fd/2"

since it doesn't treat /proc/self/fd/x specially, it does a:

fd = open("/proc/self/fd/2", O_WRONLY|O_CREAT|O_TRUNC);
write(fd, "x\n");

First /proc/self/fd is Linux specific and on Linux they are problematic. The two versions above are not equivalent when stderr is to a regular or other seekable file or to a socket (for which the latter would fail) (not to mention that it wastes a file descriptor).

That being said, if you need to write to the original stdout, you need to save it away in another fd like:

gawk -i inplace '{
   print "goes into the-file"
   print "to stdout" > "/dev/fd/3"}' the-file 3>&1

gawk does redirect stdout with in-place to the file. It's needed because for instance, you'd want:

awk -i inplace '{system("uname")}' file

to store the uname output into the file.

Related Question