为什么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