从Awk中读取stderr

Dav*_*ave 3 awk redirect string-matching

我想将SSH调试信息与其他输入分开(并记录).但是,如果我只是将stderr重定向到日志文件,我冒险将SSH的输出和主机上的远程进程的输出结合起来(可能会向stderr发送一些内容):

$ ssh -v somemachine 2> file.log
Run Code Online (Sandbox Code Playgroud)

所以,我想过滤掉那些匹配"debug1"的行:

$ ssh -v somemachine | awk '/debug1/ {print > "file.log"; next} {print}'
Run Code Online (Sandbox Code Playgroud)

好到目前为止,但是ssh的调试输出转到了stderr.所以...

$ ssh -v somemachine 2>& | awk '/debug1/ {print > "file.log"; next} {print}'
Run Code Online (Sandbox Code Playgroud)

再次挫败!我不想混合stdout和stderr.坏!

像我这样的孩子做什么?我正打算使用命名管道或一些野性的路线,但实际上,我需要知道的是如何让awk匹配来自stderr的模式.

Cas*_*bel 6

awk实际上无法看到来自stderr的输入 - 管道只管道stdout.为了做你想做的事,你将不得不重新定位.如果你不关心stdout上的内容,答案很简单:

(ssh -v hostname somecommand > /dev/null) 2>&1 | awk '/debug1/ ...'
Run Code Online (Sandbox Code Playgroud)

如果你关心什么是stdout,你将不得不做一些更复杂的事情.我相信这会奏效:

((ssh -v hostname somecommand 1>&3) 2>&1 | awk '/debug1/ ...' 1>&2) 3>&1
Run Code Online (Sandbox Code Playgroud)

按顺序,那些重定向:

  • 将原始stdout重定向到文件描述符3
  • 将stderr重定向到stdout以便awk查看
  • 将stdout重定向回stderr(最初的位置)
  • 将文件描述符3重定向回stdout(原来的位置)

PS此解决方案特定于sh/bash.Jonathan Leffler说它也适用于ksh.如果你正在使用不同的shell,你可以尝试找到与它相同的重定向的语法 - 但如果不同的shell是csh/tcsh,你可能只是搞砸了.cshells在处理stdout/stderr方面非常糟糕.