为什么ksh在子shell执行时禁用stderr?

时间:2013-07-01 06:44:47

标签: shell redirect stdout ksh stderr

该计划:

function import {
        set -x
#        read NAME < <(/usr/bin/pwd)
        NAME=$(/usr/bin/pwd)
        echo 123 >&2
        set +x
}

echo aaaaaaaaaaa
import
echo bbbbbbbbbbb
OUT=$( import 2>&1 )
echo "$OUT"
echo ccccccccccc

我希望'aaa'和'bbb'之间的输出与'bbb'和'ccc'之间的输出相同。但是ksh并非如此:

aaaaaaaaaaa
+ /usr/bin/pwd
+ NAME=/home/neuron
+ echo 123
+ 1>& 2
123
bbbbbbbbbbb
+ /usr/bin/pwd
ccccccccccc

如果我将$(...)更改为&lt; &lt;(...),stderr像往常一样工作,我有相同的输出。我在solaris和linux上试过它,它的行为相同,所以我猜这不是ksh bug。请注意,不仅'set -x'被禁用,而且'echo 123 1&gt;&amp; 2'输出消失。在bash中,代码可以像我想象的那样工作。

我的问题是'为什么'和'如何捕获函数的stdout和stderr?'

谢谢

维拉德

2 个答案:

答案 0 :(得分:1)

这看起来像是ksh中的错误(我的版本是u),并非特定于pwdstderr。 下面我可以用true和fd 3重现效果。(这允许我们继续使用shell跟踪)

效果似乎是通过分配外部进程的输出来触发的 进入函数内的变量。如果分配后面是输出 对于其他文件描述符,该输出会丢失。

这里的想法是$( ... )构造以某种方式与后续重定向冲突, 但仅当...中的代码在外部运行时。 truepwd内置函数不会触发ksh93中的子shell。

我会请David Korn确认。

function f1 {
    var=$( /bin/true )
    echo 123 >& 3
}

function f2 {
    var=$( true )
    echo 123 >& 3
}

function f3 {
    typeset var
    var=$( /bin/true )
    echo 123 >& 3
}

functions="f1 f2 f3"

typeset -tf ${functions} 

exec 3>& 1

echo ${.sh.version}

for f in ${functions}; do
    echo TEST $f
    functions $f
    echo "123 expected: "
    $f
    OUT=$(  $f 3>& 1  )
    echo "OUT='123' expected"
    echo "OUT='$OUT'" Captured output
    echo 
done 

输出:

Version JM 93u 2011-02-08
TEST f1
function f1 {
    var=$( /bin/true )
    echo 123 >& 3
}

123 expected: 
123
OUT='123' expected
OUT='' Captured output

TEST f2
function f2 {
    var=$( true )
    echo 123 >& 3
}

123 expected: 
123
OUT='123' expected
OUT='123' Captured output

TEST f3
function f3 {
    typeset var
    var=$( /bin/true )
    echo 123 >& 3
}

123 expected: 
123
OUT='123' expected
OUT='' Captured output

答案 1 :(得分:1)

确认这是一个错误。我们可以非常简单地重现它:

嵌套命令替换时出现了一些问题:

 
for command in true /bin/true; do
    a=$( ( b=$( $command ); echo 123 >& 3; ) 3>& 1 ) &&
        echo a=$a command=$command
done
a=123 command=true
a= command=/bin/true 

我们运行相同的任务两次,一次使用内置,一次使用 外部命令。我们期望得到相同的结果,但这失败了 当我们包含外部命令时。

  格伦福勒:   我相信这是在2012-08-23和2012-10-12之间修复的。

使用最新测试版进行测试:

$ ${ksh} test.sh
Version AIJM 93v- 2014-01-14
a=123 command=true
a=123 command=/bin/true
$
$ ksh test.sh
Version JM 93u 2011-02-08
a=123 command=true
a= command=/bin/true
$