gawk inplace and stdout
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
.
Just for fun, an alternate approach using only POSIX features of find
, sh
, grep
and (most notably) ex
:
find . -type f -name 'myfiles' -exec sh -c '
for f do grep -q "pat" "$f" &&
{ printf "%s\n" "$f";
printf "%s\n" "%s/pat/repl/g" x | ex "$f";
}; done' find-sh {} +
(All line breaks in the above command are optional; it can be condensed to a one-liner.)
Or, arguably more legibly:
find . -type f -name 'myfiles' -exec sh -c '
for f
do
if grep -q "pat" "$f"; then
printf "%s\n" "$f"
printf "%s\n" "%s/pat/repl/g" x | ex "$f"
fi
done' find-sh {} +
:)
(This command is untested; edits welcome if I made any goofs.)