Reputation: 173
I`m curious as to what this "2>@ stderr <@ stdin" does in this snippet of code in TCL:
if {[catch {eval exec $listCmds 2>@ stderr <@ stdin } cmdList] } { …
Based on what I know, catch
runs the command in the inner curly braces {}
and it stores the output in cmdList
. If it was successful, it doesn't enter the if
statement, and if not then it does. PS: I'm coming from a C++ background.
Upvotes: 2
Views: 187
Reputation: 247202
And the missing piece to Colin's answer is the mix of catch/exec/redirect stderr: only the spawned process's stdout will be captured in cmdList
.
if you do not redirect the process's stderr to Tcl's stderr, then exec considers any stderr output from the process to be an error:
$ 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<
when stderr is redirected, exec now doesn't know about the process's stderr, and the catch resultVar will not capture it
$ 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<
Note how the "to stderr" shows up by itself. We can now redirect it like any other stderr output:
$ 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<
Upvotes: 2
Reputation: 4382
eval exec $listCmds
runs a separate program with name and arguments taken from the variable listCmds. (Actually a more modern and safer idiom for this would be exec {*}$listCmds
).
2>@ stderr
redirects standard error output from this program to the standard error channel of the Tcl script, see https://www.tcl.tk/man/tcl/TclCmd/exec.htm#M20 .
<@ stdin
redirects the standard input of this program from the standard input channel of the Tcl script, see https://www.tcl.tk/man/tcl/TclCmd/exec.htm#M11 .
Upvotes: 4