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

为什么ksh在执行子shell时禁用stderr?,shell,redirect,stdout,ksh,stderr,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 cccccccc

该方案:

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

如果我将$(…)更改为<,这看起来像是ksh中的一个bug(我的版本是
u
),它不是特定于
pwd
stderr
。 下面我可以用
true
和fd3再现效果。(这允许我们继续使用shell跟踪)

这种效果似乎是通过分配外部进程的输出来触发的 转换为函数中的变量。如果赋值之后是输出 对于其他文件描述符,该输出会丢失

这里的想法是,
$(…)
构造在某种程度上与后续重定向冲突, 但仅当
中的代码在外部运行时。
true
pwd
内置不会触发
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 

输出:

版本JM 93u 2011-02-08
测试f1
函数f1{
var=$(/bin/true)
回声123>&3
}
123预期:
123
超出预期的123
OUT=''捕获的输出
测试f2
功能f2{
var=$(真)
回声123>&3
}
123预期:
123
超出预期的123
OUT='123'捕获的输出
测试f3
功能f3{
排版变量
var=$(/bin/true)
回声123>&3
}
123预期:
123
超出预期的123
OUT=''捕获的输出

确认这是一个bug。我们可以非常简单地复制它:

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

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
版本AIJM 93v-2014-01-14
a=123命令=true
a=123命令=/bin/true
$
$ksh test.sh
版本JM 93u 2011-02-08
a=123命令=true
a=命令=/bin/true
$ 

一个有趣的问题……我不确定除了查看源代码之外是否可以回答。我可以观察到,
bash
的行为不同,并且与您预期的更接近(出现标准错误输出),但是
ksh
没有生成您预期的所有标准错误输出。这很奇怪。我确实注意到,如果我将
/usr/bin/pwd
替换为
pwd
,我会得到相同的输出。如果我把它改成
/bin/pwd
,我会得到与上面相同的结果。乔纳森,谢谢你看这个。至少我知道我没有忽略一些显而易见的事情。我不确定我是否要研究ksh的内部结构:)目前我使用OUT=${import…}作为一种解决方法,我只需要谨慎地将所有“import”变量声明为局部变量。亨克,我想这是因为“pwd”是内置的,而/usr/bin/pwd调用的是真正的二进制。Ksh试图非常聪明地知道什么时候做子shell,什么时候不做…嗯,这是一个bug。请看下面我的第二个:很不幸,ast项目仍然没有已知bug的公共记录(已修复或未修复)。是的,太糟糕了,没有公共存储库。我们在ksh中发现了很多bug。。。它们正在ksh邮件列表中报告和固定。
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