【问题标题】:IO handling for Child Interpreters in TclTcl 中子解释器的 IO 处理
【发布时间】:2021-10-21 13:28:31
【问题描述】:

在尝试使用子解释器时,我注意到下面的代码能够关闭标准输出,然后改为写入文件。

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"

我正在尝试找到一种方法,使 stdout 也不会关闭,并且输出也被重定向到第三方工具中的文件。我在这里错过了什么?

TIA

【问题讨论】:

    标签: tcl stdout


    【解决方案1】:

    首先,close stdout;open 技巧在子解释器中不起作用的原因是父解释器打开了stdout,所以在子解释器中关闭它只会让子解释器失败访问它时,它实际上并没有关闭底层文件描述符,因此操作系统不会在该插槽中打开新的文件描述符。

    如果您使用多个线程,您也会看到这种效果。 (通道是引用计数的实体,并且非常具有线程感知能力。)

    处理第三方工具有两种简单的方法:

    1. 当您在exec(或open |…)中拥有所有重定向工具时,在子进程中运行该工具。

    2. 替换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() 系统调用。

    【讨论】:

    • 感谢您的澄清。我已经尝试替换 puts 命令,但它也不起作用,看起来我必须尝试拦截它。我会浏览你分享的链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多