Tcl 中子解释器的 IO 处理
IO handling for Child Interpreters in Tcl
在尝试使用子解释器时,我注意到下面的代码能够关闭标准输出,然后改为写入文件。
close stdout
set file [open log.txt w]
puts "hello" # prints it to a file
但是,这对儿童口译员不起作用
interp create foo
foo eval {close stdout}
foo eval {set file [open log.txt w]}
foo eval {puts "hello"} #Error: can not find channel named "stdout"
我正在尝试找到一种方法,既不关闭标准输出,又将输出重定向到第三方工具中的文件。我在这里错过了什么?
TIA
首先,close stdout;open
技巧在 child 解释器中不起作用的原因是 parent 解释器 也 stdout
打开,所以在 child 中关闭它只会让 child 失去对它的访问权限,它实际上并没有关闭底层文件描述符,因此 OS 不会t 在那个插槽中打开新的文件描述符。
如果您使用多线程,您也会看到这种效果。 (频道是 reference-counted 个实体,而且非常 thread-aware。)
有两种简单的方法来处理 third-party 工具:
运行 子进程中的工具,当您拥有 exec
(或 open |…
)中的所有重定向工具时。
替换 puts
命令,以便您可以在脚本级别 拦截写入 并做正确的事情。
rename puts _real_puts
proc puts args {
global accumulator
if {[llength $args] == 1} {
append accumulator [lindex $args 1] "\n"
return
} elseif {[llength $args] == 2 && [lindex $args 1] eq "-nonewline"} {
append accumulator [lindex $args 1]
return
}
tailcall _real_puts {*}$args
}
如果该工具明确使用 stdout
。
,您可能需要比这更复杂一些
从 C 级别拦截对 Tcl stdout
通道的写入是可能的,但需要类似 this.
的东西
从 C 级别拦截对标准输出文件描述符的直接写入通常是不可能的,当然也不容易。您需要弄乱 dup()
和 dup2()
系统调用。
在尝试使用子解释器时,我注意到下面的代码能够关闭标准输出,然后改为写入文件。
close stdout
set file [open log.txt w]
puts "hello" # prints it to a file
但是,这对儿童口译员不起作用
interp create foo
foo eval {close stdout}
foo eval {set file [open log.txt w]}
foo eval {puts "hello"} #Error: can not find channel named "stdout"
我正在尝试找到一种方法,既不关闭标准输出,又将输出重定向到第三方工具中的文件。我在这里错过了什么?
TIA
首先,close stdout;open
技巧在 child 解释器中不起作用的原因是 parent 解释器 也 stdout
打开,所以在 child 中关闭它只会让 child 失去对它的访问权限,它实际上并没有关闭底层文件描述符,因此 OS 不会t 在那个插槽中打开新的文件描述符。
如果您使用多线程,您也会看到这种效果。 (频道是 reference-counted 个实体,而且非常 thread-aware。)
有两种简单的方法来处理 third-party 工具:
运行 子进程中的工具,当您拥有
exec
(或open |…
)中的所有重定向工具时。替换
puts
命令,以便您可以在脚本级别 拦截写入 并做正确的事情。rename puts _real_puts proc puts args { global accumulator if {[llength $args] == 1} { append accumulator [lindex $args 1] "\n" return } elseif {[llength $args] == 2 && [lindex $args 1] eq "-nonewline"} { append accumulator [lindex $args 1] return } tailcall _real_puts {*}$args }
如果该工具明确使用
,您可能需要比这更复杂一些stdout
。
从 C 级别拦截对 Tcl stdout
通道的写入是可能的,但需要类似 this.
从 C 级别拦截对标准输出文件描述符的直接写入通常是不可能的,当然也不容易。您需要弄乱 dup()
和 dup2()
系统调用。