是否可以使用gawk
's-i inplace
选项并打印内容stdout
?
例如,如果我想更新一个文件,并且如果有任何更改,则打印文件名和更改后的行,stderr
我可以执行类似的操作
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;}' {} +
但有没有一种方法可以替代stdout
,或者有一种更干净的方法将该块打印到备用流?
答案1
您应该使用/dev/stderr
or/dev/fd/2
代替/proc/self/fd/2
.gawk
处理/dev/fd/x
和/dev/stderr
本身(无论系统是否有这些文件)。
当您执行以下操作时:
print "x" > "/dev/fd/2"
gawk
执行write(2, "x\n")
, while 当您执行以下操作时:
print "x" > "/proc/self/fd/2"
因为它没有/proc/self/fd/x
特殊处理,所以它做了:
fd = open("/proc/self/fd/2", O_WRONLY|O_CREAT|O_TRUNC);
write(fd, "x\n");
首先/proc/self/fd
是 Linux 特定的,在 Linux 上它们是有问题的。当 stderr 是常规文件或其他可查找文件或套接字(后者会失败)时,上面的两个版本并不等效(更不用说它浪费了文件描述符)。
话虽如此,如果您需要写入原始标准输出,则需要将其保存在另一个 fd 中,例如:
gawk -i /usr/share/awk/inplace.awk '{
print "goes into the-file"
print "to stdout" > "/dev/fd/3"}' the-file 3>&1
gawk
确实将 stdout 就地重定向到文件。它是必需的,因为例如,您想要:
awk -i /usr/share/awk/inplace.awk '{system("uname")}' file
将uname
输出存储到file
.
任何状况之下,不使用-i inplace
as尝试首先从当前工作目录gawk
加载inplace
扩展(asinplace
或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk
的路径可能会有所不同,请参阅输出inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
答案2
只是为了好玩,另一种方法仅使用find
、sh
和grep
(最值得注意的是)的 POSIX 功能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 {} +
(上述命令中的所有换行符都是可选的;它可以压缩为一行。)
或者,可以说更清晰:
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 {} +
:)
(此命令未经测试;如果我犯了任何错误,欢迎编辑。)