该计划:
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?'
维拉德
答案 0 :(得分:1)
这看起来像是ksh中的错误(我的版本是u
),并非特定于pwd
或stderr
。
下面我可以用true
和fd 3重现效果。(这允许我们继续使用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
输出:
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
$