原地呆呆和标准输出

原地呆呆和标准输出

是否可以使用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/stderror/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 inplaceas尝试首先从当前工作目录gawk加载inplace扩展(asinplace或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk的路径可能会有所不同,请参阅输出inplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

答案2

只是为了好玩,另一种方法仅使用findshgrep(最值得注意的是)的 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 {} +

:)


(此命令未经测试;如果我犯了任何错误,欢迎编辑。)

相关内容