我发现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
不确定这是否要求太多。我希望有人可以解决这个问题。感谢。
答案 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]
为$ret
,0
正确排序:
$msg
它是如何工作的?诀窍是|&
,它在管道到另一个进程时执行合并。 (我们使用a
b
c
因为它只是通过事情而不会干扰。)
如果您使用的是Tcl 8.6(测试版),则可以使用chan pipe
生成一个频道,您可以将cat
和stdout
重定向到2>@ fileId
form,但这对你没那么有用。 (你知道8.3已经过时了吗?甚至不再支持8.4; 8.5是推荐用于生产级代码的目标。)
答案 1 :(得分:-1)
使用source
命令代替exec
,因为您要从另一个tcl脚本中调用tcl脚本:
set ret [catch {source $cmd} msg]