3

该程序:

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

如果我将 $( ... ) 更改为 < <(...),stderr 将照常工作,并且我有相同的输出。我在 solaris 和 linux 上试过了,它的行为是一样的,所以我猜这不是 ksh 错误。请注意,不仅“set -x”被禁用,“echo 123 1>&2”输出也消失了。在 bash 中,代码按我的设想工作。

我的问题是“为什么”和“如何捕获函数的标准输出和标准错误?”

谢谢

弗拉德

4

2 回答 2

1

这看起来像是 ksh 中的一个错误(我的版本是u),它不是特定于pwdorstderr的。下面我可以用truefd 3 重现效果。(这让我们可以继续使用 shell 跟踪)

该效果似乎是通过将来自外部进程的输出分配给函数内部的变量来触发的。如果分配之后是输出到其他文件描述符,则该输出将丢失。

这里的想法是该$( ... )构造在某种程度上与后续重定向发生冲突,但仅当代码在...外部运行时才会发生。和内置true函数pwd不会触发ksh93.

我会请大卫科恩确认。

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
于 2014-01-18T00:15:27.573 回答
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 

我们两次运行相同的分配,一次使用内置命令,一次使用外部命令。我们希望得到相同的结果,但是当我们包含外部命令时这会失败。

Glenn Fowler:我相信这是在 2012-08-23 和 2012-10-12 之间修复的

使用最新的 beta 测试:

$ ${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
$ 
于 2014-01-18T00:43:01.793 回答