这一段在这段 TCL 代码中做了什么

What does this certain piece do in this snippet of TCL code

我很好奇“2>@stderr <@stdin”在 TCL 的这段代码中做了什么:

if {[catch {eval exec $listCmds 2>@ stderr <@ stdin } cmdList] } { …

据我所知,catch 运行内花括号 {} 中的命令,并将输出存储在 cmdList 中。如果成功,则不会进入 if 语句,如果不成功,则进入。 PS:我有 C++ 背景。

eval exec $listCmds 运行一个单独的程序,其名称和参数取自变量 listCmds。 (实际上,更现代、更安全的用法是 exec {*}$listCmds)。

2>@ stderr 将此程序的标准错误输出重定向到 Tcl 脚本的标准错误通道,请参阅 https://www.tcl.tk/man/tcl/TclCmd/exec.htm#M20

<@ stdin 从 Tcl 脚本的标准输入通道重定向此程序的标准输入,参见 https://www.tcl.tk/man/tcl/TclCmd/exec.htm#M11

缺少的部分是 catch/exec/redirect 标准错误的混合: 派生进程的 stdout 将在 cmdList.

中捕获
  • 如果您不将进程的 stderr 重定向到 Tcl 的 stderr,那么 exec 会将进程的任何 stderr 输出视为错误:

    $ echo '
        set rc [catch {exec sh -c {echo to stdout; echo to stderr >&2}} result]
        puts "rc=$rc result=>$result<"
    ' | tclsh
    rc=1 result=>to stdout
    to stderr<
    
  • 当 stderr 被重定向时,exec 现在不知道进程的 stderr,并且 catch resultVar 不会捕获它

    $ echo '
        set rc [catch {exec sh -c {echo to stdout; echo to stderr >&2} 2>@stderr} result]
        puts "rc=$rc result=>$result<"
    ' | tclsh
    to stderr
    rc=0 result=>to stdout<
    

    请注意 "to stderr" 是如何单独出现的。我们现在可以像任何其他 stderr 输出一样重定向它:

    $ echo '
        set rc [catch {exec sh -c {echo to stdout; echo to stderr >&2} 2>@stderr} result]
        puts "rc=$rc result=>$result<"
    ' | tclsh 2>/dev/null
    rc=0 result=>to stdout<