【问题标题】:How can I redirect stdout into a file in tcl如何将标准输出重定向到 tcl 中的文件
【发布时间】:2011-12-16 07:21:13
【问题描述】:

如何将 proc 输出重定向到 tcl 中的文件,例如,我有一个 proc foo,并且想将 foo 输出重定向到文件栏。但是得到了这个结果

% proc foo {} { puts "hello world" }
% foo
hello world
% foo > bar
wrong # args: should be "foo"

【问题讨论】:

    标签: file io tcl


    【解决方案1】:

    如果您无法更改代码以获取要写入的频道的名称(最强大的解决方案),您可以使用技巧将 stdout 重定向到文件:重新打开

    proc foo {} { puts "hello world" }
    proc reopenStdout {file} {
        close stdout
        open $file w        ;# The standard channels are special
    }
    
    reopenStdout ./bar
    foo
    reopenStdout /dev/tty   ;# Default destination on Unix; Win equiv is CON:
    

    请注意,如果您这样做,您将无法跟踪您最初的 stdout 被定向到的位置(除非您使用 TclX 的 dup 来保存副本)。

    【讨论】:

      【解决方案2】:

      这应该可行:

      % proc foo {} { return "hello world" }
      % foo
      hello world
      % exec echo [foo] > bar
      % exec cat bar
      hello world
      % exec echo [foo] >> bar
      % exec cat bar
      hello world
      hello world
      % 
      

      【讨论】:

        【解决方案3】:

        一般来说,我会推荐 Donal Fellows 在his answer 中建议的标准输出重定向。

        有时这可能是不可能的。也许 Tcl 解释器链接到一个复杂的应用程序,它自己对输出应该去哪里有一个奇特的想法,然后你不知道如何恢复标准输出通道。

        在这些情况下,您可以尝试重新定义puts 命令。这是一个关于如何做到这一点的代码示例。在普通的 Tcl 中,可以通过renaming 将命令重新定义为安全名称,并创建一个包装程序,以安全名称调用原始命令 - 或根本不调用,具体取决于您的预期功能。

        proc redirect_file {filename cmd} {
            rename puts ::tcl::orig::puts
        
            set mode w
            set destination [open $filename $mode]
        
            proc puts args "
                uplevel \"::tcl::orig::puts $destination \$args\"; return
            "
        
            uplevel $cmd
        
            close $destination
        
            rename puts {}
            rename ::tcl::orig::puts puts
        }
        

        您还可以将文本重定向到变量中:

        proc redirect_variable {varname cmd} {
            rename puts ::tcl::orig::puts
        
            global __puts_redirect
            set __puts_redirect {}
        
            proc puts args {
                global __puts_redirect
                set __puts_redirect [concat $__puts_redirect [lindex $args end]]
                set args [lreplace $args end end]
                if {[lsearch -regexp $args {^-nonewline}]<0} {
                    set __puts_redirect "$__puts_redirect\n"
                }
                return
            }
        
            uplevel $cmd
        
            upvar $varname destination
            set destination $__puts_redirect
            unset __puts_redirect
        
            rename puts {}
            rename ::tcl::orig::puts puts
        }
        

        Tcl'ers Wiki 在更复杂的应用程序中还有另一个 interesting example of redefining puts。也许这也很鼓舞人心。

        【讨论】:

          【解决方案4】:

          目前,当您键入foo &gt; bar 时,Tcl 正在尝试运行带有 2 个参数的 foo proc,因为它不存在,您会收到错误消息。我可以想出两种方法来解决这个问题。

          您可以在顶层重定向,因此当您运行 tclsh tclsh &gt; bar 时,所有输出都将被重定向,但我怀疑这是否是您想要的。

          您可以更改 foo 以便它接受打开的文件作为参数并写入:

          proc foo {fp} {
             puts $fp "some text"
          }
          
          set fp [open bar w]
          foo $fp
          close $fp
          

          【讨论】:

            【解决方案5】:

            为了实现这一点,我将对我的 Tcl proc 的调用封装在一个 shell 脚本中。这适用于 unix,不确定其他操作系统。

            文件 - foo.tcl:

            proc foo {} {puts "Hi from foo"}

            file - foo.csh(任何 shell 脚本都可以,我在这个例子中使用 csh): enter code here

            #!/usr/bin/tclsh
            源 foo.tcl
            eval "foo $argv"

            文件 - main.tcl:

            执行 foo.csh > ./myoutput.txt

            当然,这些命令可以通过将它们包装在诸如 catch 等安全措施中而变得“花哨”......为了清楚起见,我没有包括它们,但我建议使用它们。我还包括了不需要的 $argv,因为 proc foo 不接受 args,但通常 IRL 会有 args。如果您只想附加到文件而不是覆盖它,请务必使用 >>。

            【讨论】:

              【解决方案6】:

              感谢分享 CFI。 我也想做出贡献。 因此,我进行了一些更改以重新定义 put on dump 到 startlog 上的文件,并在需要时结束 endlog 上的日志记录到文件。 这将在标准输出上打印并将标准输出重定向到文件。

              proc startlog {filename } {
                  rename puts ::tcl::orig::puts
              
                  set mode w
                  global def destination logfilename
                  set destination [open $filename $mode]
                  set logfilename $filename
              
                  proc puts args "
                      uplevel 2 \"::tcl::orig::puts \$args\"
                      uplevel \"::tcl::orig::puts $destination \{\$args\}\"; return
                  "
              }
              
              proc endlog { } {
                  global def destination logfilename  
                  close $destination
                  rename puts {}
                  rename ::tcl::orig::puts puts
                  cleanlog $logfilename
                  puts "name of log file is $logfilename"
              }
              
              proc cleanlog {filename } {  
                  set f [open $filename]
                  set output [open $filename\.log w]
                  set line1 [regsub -all {\-nonewline stdout \{} [read $f] ""]
                  set line2 [regsub -all {stdout \{} $line1 ""]
                  set line3 [regsub -all {\}} $line2 ""]
                  set line4 [regsub -all {\{} $line3 ""]
                  puts $output $line4
                  close $output
                  file rename -force $filename.log $filename
              }
              

              【讨论】:

                【解决方案7】:

                我们也可以这样尝试

                % proc foo {} { return "hello world" }
                
                % foo
                
                hello world
                
                % set fd [open "a.txt" w]
                
                file5
                
                % set val [foo]
                
                hello world
                
                % puts $fd $val
                
                % close $fd
                
                % set data [exec cat a.txt]
                
                hello world
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-09-29
                  • 2015-05-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多