tcl exec先读stdout然后stderr?

时间:2010-08-23 06:36:03

标签: exec tcl stdout stderr

我发现tcl exec命令首先从stdout返回字符串然后是stderr。例如,我的以下“测试脚本”按此顺序生成消息:

puts "test started"
puts stderr "some non-fatal error goes to stderr"
puts "test passed"

然后我执行这样的脚本:

set ret [ catch { exec sh -c $cmd } msg ]

我从$ msg获得的是:

test started
test passed
some non-fatal error goes to stderr

这真的让我很难得到正确的结果。

如果知道是否有可能按顺序从stdout和stderr获取消息,有人可以通知,并且:

1)请不要像这样重定向,这样可以确保它们全部按顺序排列:

set ret [ catch {exec $cmd >&log.txt} msg ]

2)我必须在我的 tcl脚本中调用 tcl脚本,抱歉

3)我也不能直接获取.tcl测试脚本,因为在两者之间调用了其他脚本,如果我的tcl脚本只是那个 tcl脚本,它就无法工作。

我正在使用tclsh 8.3

不确定这是否要求太多。我希望有人可以解决这个问题。感谢。

2 个答案:

答案 0 :(得分:5)

首先,让我们为测试目的定义一个简单的命令,我们可以肯定会测试我们需要的东西:

set cmd "echo a; echo b >&2; echo c"

接下来,我们使用一些额外的帮助来处理stdout和stderr流的合并(为了清楚起见,将命令分成几行,以便我们可以看到catch包装器的位置以及包裹的{{ {1}}是):

exec

如果我们对此进行测试,我们会发现set ret [catch { exec sh -c $cmd |& cat } msg] $ret0正确排序:

$msg

它是如何工作的?诀窍是|&,它在管道到另一个进程时执行合并。 (我们使用a b c 因为它只是通过事情而不会干扰。)

如果您使用的是Tcl 8.6(测试版),则可以使用chan pipe生成一个频道,您可以将catstdout重定向到2>@ fileId form,但这对你没那么有用。 (你知道8.3已经过时了吗?甚至不再支持8.4; 8.5是推荐用于生产级代码的目标。)

答案 1 :(得分:-1)

使用source命令代替exec,因为您要从另一个tcl脚本中调用tcl脚本:

set ret [catch {source $cmd} msg]