【问题标题】:tcl exec reads stdout first then stderr?tcl exec 先读取标准输出然后读取标准错误?
【发布时间】:2010-08-23 06:36:02
【问题描述】:

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

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) 我必须在 my tcl 脚本中调用 that tcl 脚本,对不起

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

我正在使用 tclsh 8.3

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

【问题讨论】:

标签: exec tcl stdout stderr


【解决方案1】:

首先,让我们为测试目的定义一个简单的命令,我们可以确定它会测试我们需要的内容:

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

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

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

如果我们对此进行测试,我们会发现$ret0,而$msg 是正确排序的:

a
b
c

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

如果您使用的是 Tcl 8.6(测试版),您可以使用 chan pipe 生成一个频道,您可以使用 2>@ fileId formstdoutstderr 重定向到该频道,但这对您来说不是那么有用。 (您知道 8.3 已经过时了吗?甚至不再真正支持 8.4;建议使用 8.5 来定位生产级代码。)

【讨论】:

  • 如果您使用open 制作管道,您会有更多选择,但拼接起来更复杂。
  • 太棒了!!凉爽的!!虽然不是很清楚机制,但我很高兴看到您的帖子并使用此代码。谢谢!
  • 机制是“|&将stdout和stderr都发送到管道中的下一个进程”。我使用cat 传递它。
猜你喜欢
  • 1970-01-01
  • 2014-07-08
  • 2019-12-05
  • 2013-02-24
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多