在Tcl中分离stdout和stderr会除去stderr的最后一行

在Tcl中分离stdout和stderr会除去stderr的最后一行,tcl,stdout,stderr,Tcl,Stdout,Stderr,我不是Tcl程序员,但我需要修改一个Tcl脚本,该脚本调用一个外部命令并尝试分离stdout和stderr。下面是脚本当前如何执行此操作的一个简单示例 #!/usr/bin/tclsh8.4 set pipe [open "|cmd" r] while {[gets $pipe line] >= 0} {puts $line} catch "close $pipe" errorMsg puts "$errorMsg" 这里,cmd是一个外部命令,为了这个示例,我将用下面的shell脚本

我不是Tcl程序员,但我需要修改一个Tcl脚本,该脚本调用一个外部命令并尝试分离
stdout
stderr
。下面是脚本当前如何执行此操作的一个简单示例

#!/usr/bin/tclsh8.4

set pipe [open "|cmd" r]
while {[gets $pipe line] >= 0} {puts $line}
catch "close $pipe" errorMsg
puts "$errorMsg"
这里,
cmd
是一个外部命令,为了这个示例,我将用下面的shell脚本替换它。(我正在Linux机器上工作,但是您可以修改它以写入
stdout
stderr
,但是这适合您的系统。)

当我执行
cmd
时,我得到了预期的以下四行:

 % ./cmd
A
B
C
D
但是,当我执行我的Tcl脚本时,我得到:

 % ./test.tcl
A
B
D
这是一个更普遍现象的例子,即
catch
似乎吞下了
stderr
的最后一行以外的所有内容

对我来说,实现这一点的“明显”方法是尝试模仿
stdout
,它显然可以工作并打印输出的所有行。但是,当前的实现是基于使用
open“| cmd”
获取Tcl通道,这需要运行外部命令。我不知道如何在不打开外部命令的情况下创建通道,即使我知道,这种方法也会出现后续问题。(我如何将
close
的输出输入通道?如果我需要打开一个新通道来获得我正在关闭的每个通道的输出,那么我不需要无限多的通道吗?)

如果有人知道为什么
errorMsg
会删除初始行或其他不存在此问题的方法,请告诉我


我知道会出现这种情况,所以我会提前说,短期内切换到Tcl 8.5可能不是我的选择,因为我不控制运行此脚本的环境。

有趣的是,如果您将cmd脚本的最后一行更改为
echo“D”,它将按预期工作>>/dev/stderr
@SchelteBron这很吸引人,但有点奇怪,因为我不认为
>
之间的区别对
stdout
stderr
很重要。这表明我可以通过更改
cmd
而不是Tcl脚本来修复该行为,在我的例子中,Tcl脚本对我来说实际上更容易。我正在阅读更多关于如何工作的内容,这可能是unix文件系统如何处理
stderr
的文件描述符与Tcl如何存储文件描述符之间有趣的交互作用的一个例子。这与Tcl无关,而是与Bash有关。请参阅上的讨论。那么,实际上,您应该将cmd示例更改为使用
csh
。尽管如此,它仍然是一个执行shell脚本的问题,与Tcl无关。
 % ./test.tcl
A
B
D