11.4文件描述符

大多数shell(如果不是全部)(包括Bash、Zsh、Ash)在stderr,即使是子shell。这可能会导致不需要的内容如果您打算捕获内部命令的标准错误输出:

$ash-x-c'(eval“echo foo>&2”)2>标准错误'$猫标准差+评估echo foo>&2+回波foofoo公司$bash-x-c'(eval“echo-foo>&2”)2>stderr'$猫标准差+eval“echo foo>&2”++回波foofoo公司$zsh-x-c'(eval“echo foo>&2”)2>标准错误'
#此处删除了启动文件的痕迹。$猫标准差+zsh:1>评估echo foo>&2+zsh:1>回波foofoo公司

一个解决方法是删除不感兴趣的行,希望不删除好的。

如果您打算重定向标准错误和标准输出,首先重定向标准输出。这与HP-UX、,因为它的shell错误地处理了标准错误重定向时的跟踪第一:

$sh-x-c“:2>err>out”+ :+2>错误$猫的错误1> 退出

不要试图重定向命令替换的标准错误。必须完成里面命令替换。运行时:`cd/zorglub`2>/dev/null'期望错误消息逃逸,而':`cd/zorglub 2>/dev/null`'工作正常。

另一方面,一些shell,如Solaris或FreeBSD/垃圾桶/桶,在执行之前警告缺少程序重定向。因此,为了无提示地检查程序是否存在需要对子壳或支撑组执行重定向:

$/bin/sh-c“nosuch 2>/dev/null”nosuch:未找到$/bin/sh-c'(nosuch)2>/dev/null'$/bin/sh-c“{nosuch;}2>/dev/null”$bash-c“nosuch 2>/dev/null”

FreeBSD 6.2 sh可以混合壳体管道。

值得注意的是,Zsh(但不是Ash或Bash)使其成为可能但在作业中:'foo=`cd/zorglub`2>/dev/null”。

一些贝壳,比如,不识别双向重定向('<>’). 即使在识别它的壳上,它也是在fifos上使用不可移植:Posix不需要读写支持对于命名管道,Cygwin不支持:

$mkfifo-fifo$执行5<>fifo$回波hi>&5bash:echo:写入错误:发送时发生通信错误

此外短跑0.5.6之前错误截断使用“”时的常规文件<>’:

$echo>文件$bash-c“:1<>文件”;cat文件$破折号-c“:1<>文件”;cat文件每年$rm

Solaris 10/垃圾桶/桶执行重定向的复合命令在子壳中,而其他壳不:

$/bin/sh-c’foo=0;{foo=1;}2>/dev/null;echo$foo'0$ksh-c’foo=0;{foo=1;}2>/dev/null;echo$foo'1$bash-c’foo=0;{foo=1;}2>/dev/null;echo$foo'1

当面向旧系统时,不要重定向相同的文件描述符好几次,因为你在Ultrix的领导下注定会失败。

ULTRIX V4.4(版本69)系统#31:1995年8月10日星期四19:42:23 GMTUWS V4.4(第11版)$评估“回声物质>饱满度”>空隙非法io$eval“(回声物质>饱满度)”>空洞非法io$(eval'(回声物质>饱满度)')>空洞输出重定向不明确。

当然,在每种情况下,预期结果都是丰满包含问题'和空隙为空。然而,这个错误是对于现代平台来说,这可能不是一个实际问题。

Solaris 10第页将尝试优化:命令(即使它被重定向)在第一次迭代后的循环中,或在第一次调用后的shell函数:

$对于1 2 3中的i;做:>x$i;完成$长x*x1个$f(){:>1美元;};f y1;fy2;fy3;$是的*y1个

作为一种解决方法,回声评估可以使用。

不要依赖于文件描述符0、1和2在附属计划。如果这些描述符中的任何一个被关闭操作系统可能会为中的描述符打开未指定的文件新进程图像。Posix 2008表示,只有在子程序设置了用户ID或组ID,但HP-UX 11.23设置了它甚至适用于普通程序,Posix的下一版本将允许HP-UX行为。

如果希望将大于2的文件描述符继承到子级中进程,则必须使用特定于该命令的重定向或包含子shell或命令组,而不是依赖执行官在壳中。克什以及HP-UX第页,使用打开的2以上的文件描述符执行官n个>文件'由后续关闭'执行官'(例如运行程序或脚本的fork-and-exec所涉及的):

$echo“echo hello>&5'>k$/bin/sh-c'执行5>t;肯尼亚先令/k;执行5>&;猫t你好$bash-c'执行5>t;肯尼亚先令/k;执行5>&;猫t你好$ksh-c'执行5>t;肯尼亚先令/k;执行5>&;猫t./k[1]:5:无法打开[错误的文件号]$ksh-c'(ksh./k)5>吨;猫t'你好$ksh-c'{ksh./k;}5>t;猫t'你好$ksh-c'5>t ksh/k;猫t你好

不要依赖复制关闭的文件描述符来导致错误。使用Solaris 10/垃圾桶/桶,失败的复制是无声的忽略,这可能会导致原始文件意外泄漏描述符。在此示例中,观察泄漏到标准输出:

$bash-c’echo hi>&3’3>&;echo$?bash:3:错误的文件描述符1$/bin/sh-c’echo hi>&3’3>&;echo$?你好0

幸运的是,尝试关闭已关闭的文件描述符将便携成功。同样,可以安全地使用n个<&-'或'n个>&-'用于关闭文件描述符,即使它与文件描述符的读/写模式不匹配已用打开。

DOS变量无法重命名或删除打开的文件,例如mv foo栏>foo'或'rm-foo>foo',尽管这是在Posix主机之间完全可移植。

一些古代系统保留了一些文件描述符。按照惯例,文件描述符3已打开到/开发/tty当您登录时第八版(1985年)至第十版Unix(1989年)。文件描述符4对Stardent/Kubota Titan(大约1990年),尽管我们现在不记得是什么了。这两个系统都是过时了,所以现在可以像对待任何文件描述符一样对待文件描述符3和4其他文件描述符。

另一方面,您不能移植性地使用多git文件描述符。短跑和Solaris克什不理解任何文件描述符大于'9’:

$bash-c'exec 10>&&';echo$?0$ksh-c“执行9>&-”;echo$?0$ksh-c“执行10>&-”;echo$?ksh[1]:exec:10:未找到127$破折号-c“exec 9>&-”;echo$?0$破折号-c“exec 10>&-”;echo$?exec:1:10:未找到2