我正在使用TCL-Expect,我正在脚本中执行脚本。是否可以关闭stderr流并将所有其他消息写入stdout?
set runcmd [ exec $SCRIPTS_PATH/config $build_tag -u 2>&- >&stdout]
# Just in case...
if { [catch $runcmd res] } {
send_user "Failed to run command due to: $res"
}
上面代码的当前行为不会向stdout显示任何内容,但会避免使用stderrs,也不会显示。
答案 0 :(得分:1)
要抑制stderr,你可以这样做:
exec config $build_tag -u 2>/dev/null
答案 1 :(得分:1)
Tcl(和期望)exec
命令定义了自己的重定向:请参阅http://tcl.tk/man/tcl8.5/TclCmd/exec.htm - 您不能只假设sh / bash重定向可以正常工作。
你想要
if { [catch {exec $SCRIPTS_PATH/config $build_tag -u 2>/dev/null} res] != 0 } {
send_user "Failed to run command due to: $res"
}
如果要将stderr发送到stdout,请使用2>@1
(参见手册页)
如果要将命令声明为变量,请执行以下操作:
set runcmd [list exec $SCRIPTS_PATH/config $build_tag -u 2>/dev/null]
if { [catch $runcmd res] != 0 } {
send_user "Failed to run command due to: $res"
}
如果你真的想使用shell重定向,你必须在shell中执行命令:
set runcmd [list exec sh -c "$SCRIPTS_PATH/config $build_tag -u 2>&1"]
我没有看到2>&-
在bash手册页中有效:n<&-
关闭文件描述符 n 。
答案 2 :(得分:1)
如果我正在运行一个命令,想要向stderr喷出无关的垃圾,我想要压制它,我会用2>/dev/null
抛弃它。
# The “list” is important! It says “build a list here” instead of direct evaluation
set runcmd [list $SCRIPTS_PATH/config $build_tag -u]
exec {*}$runcmd 2>/dev/null
如果$SCRIPTS_PATH/config
具有非零退出代码,那仍然会产生错误,但这通常是正确的。抓住它:
if {[catch { exec {*}$runcmd 2>/dev/null }]} {
# An error has been trapped
}
Tcl没有提供一种在stderr完全关闭的情况下运行子进程的方法;真的是一个非常奇怪的状态。重定向到/ dev / null更有可能是有用和理智的。
另一方面,如果你想要将错误运行到外部Tcl脚本的stderr而不会导致错误(如果生成了这些消息){{1>非常刺激性的{{1 (有时) - 所以来自exec
的任何错误都只来自子进程退出代码 - 这是通过不同的重定向完成的,如下所示:
exec
这是因为exec {*}$runcmd 2>@stderr
通常会捕获子进程stderr以用作更好的错误消息的源。由于某些命令使用stderr来打印错误消息但实际上没有正确地错误输出,而其他命令将记录信息写入stderr,而不仅仅是错误消息,这一切都变得更加复杂。 (这完全是一个沼泽地,它是很多人在很长一段时间内将代码混杂在一起的结果.Tcl只是试图在这个领域尽其所能;我不相信它是正确的,但过去的设计选择被现在依赖它们的脚本数量所成圣。)
我不会做的是将exec
或重定向放在exec
命令调用中;我认为这太令人困惑了。我更喜欢更直接地表达“属于Tcl的东西”。这只是一个品味问题,但我认为它更清楚。它还允许我考虑构造命令,然后将其发送到从属shell进行评估;内部语法是不同的(shell,而不是Tcl),但你可以这样做:
list
这在逻辑上非常相同,对某些事情更好。
如果您仍在使用8.4(或更早版本!),则无法使用set runcmd "$SCRIPTS_PATH/config $build_tag -u"
exec /bin/sh -c $runcmd 2>/dev/null
语法。如果{*}
由$runcmd
构建,那么您可以将其作为替代方案。
list
理论上,你应该写一下:
eval exec $runcmd 2>/dev/null
但那是糟糕的以及eval [list exec] [lrange $runcmd 0 end] [list 2>/dev/null]
可能不是规范格式列表时唯一需要的东西。 (我们在8.5中添加了列表扩展语法,因为我们再也不想看到那种怪异了,因为我们发现在所有情况下都非常小心,因为它会导致错误导致错误。)
如果您使用的是8.4并且不是非常严格地被迫坚持使用它,请升级到至少8.5; 8.4不再支持。 (我们确实支持了十多年......)8.5与8.4非常兼容,但值得检查你的代码是否真的有用。要小心谨慎。如果遇到问题,请在Stack Overflow上询问关于修复它的问题。尽管如此,我的脚本在迁移它们时都是Just Worked所以值得一试。