Linux Bash Shell高级重定向操作--深入了解标准错误输出和标准输出

    一般来说一个程序的输出可分为标准输出和标准错误输出,这个已经众人皆知。但打印到屏幕上的输出一定是标准输出吗?答案是否定的!默认打印到屏幕上的输出不一定是标准输出。

举一个最常用的例子。我想通过nginx -v或ngxin -V查看nginx的版本信息,如果我只想要最后面的版本号,那我只需要用awk或cut处理就行。例如想获得“nginx version: nginx/1.2.7”中的“1.2.7”,理想的命令行是“nginx -v | grep nginx | cut -d '/' -f2”或“nginx -v | cut -d '/' -f2”或“nginx -v | grep nginx | awk -F '/' '{print $2}'”,但实际上依然会输出“nginx version: nginx/1.2.7”,你可能认为是不是我用echo的方法就能实现呢?也不是的。例如用命令行“echo $(nginx -v) | grep nginx | awk -F '/' '{print $2}'”或“echo $(nginx -v) | grep nginx | cut -d '/' -f2”也是不行的。

    但怎么就行了呢?答案是使用“2>&1 |”或“|&”(二者等价),将命令1的标准错误输出作为命令2的标准输入。

    解释:nginx -v的默认输出是标准错误输出(标准错误输出并不代表是执行返回值为1,如使用“echo $?”查看返回值为0(已正确执行))。例如我们可以测试一下,将“输出”(此时假设不知道它是标准输出还是标准错误输出)重定向到文件,再查看文件的内容。例如执行“nginx -v > test”时屏幕会输出“nginx version: nginx/1.2.7”,这表明屏幕上出现的是标准错误输出。当然了,你也可以用查看文件的方式“cat test”发现有这个文件,但内容却是空的,也说明这个命令没有输出标准输出。

    关于列截取。但在列截取的工具选择上,如果是可以将单字符作为间隔符,则最好是使用cut,经过测试发现,awk不能直接处理标准错误输出,即使将标准错误输出转化成标准输出后依然会有问题。例如“echo $(nginx -v) |& grep nginx | awk -F '/' '{print $2}'”和“echo $(nginx -v) | grep nginx | awk -F '/' '{print $2}'”以及“echo $(nginx -v) 2>&1 | grep nginx |& awk -F '/' '{print $2}'”的结果是完全一样的。而cut能处理标准错误输出但是有一种情况例外,“nginx -v |& grep nginx | awk -F '/' '{print $2}'”可以输出正确结果,“1.2.7”。

    除此之外,在测试的过程中发现,grep也不能直接处理标准错误输出。“echo $(nginx -v) 2>&1 | grep nginx > test”和“echo $(nginx -v) |& grep nginx > test”的结果都是test中没有任何内容,它只会输出“nginx version: nginx/1.2.7”。换成“nginx -v |& grep nginx”就能。

    tee也不能(tee不是标准的bash指令)!有点坑不是吗?

    参考:Bash Reference Manual的3.2.2 Pipelines http://www.gnu.org/software/bash/manual/bashref.html#Pipelines

    If ‘|&’ is used, the standard error ofcommand1is connected tocommand2’s standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error is performed after any redirections specified by the command.

    因此,在类似调试出现问题时,确认是否是标准错误输出以及是否要处理也是一个值得考虑的点。




本文转自 urey_pp 51CTO博客,原文链接:http://blog.51cto.com/dgd2010/1419955,如需转载请自行联系原作者

上一篇:字符编码拦截器/过滤器无效的原因


下一篇:nmap端口状态解析