2011-12-16 183 views
7

如何在tcl中將proc輸出重定向到文件中,例如,我有一個proc foo,並且希望將foo輸出重定向到文件欄。但是,當你鍵入foo > bar的Tcl正試圖運行FOO PROC即需要2參數,因爲這不存在,您收到錯誤消息得到這個結果如何將stdout重定向到tcl文件中

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

回答

0

目前。我可以想到解決這個問題的兩種方法。

你可以在頂層重定向,所以當你運行tclsh tclsh > bar時,所有的輸出都會被重定向,但是我懷疑這是你想要的。

,使其接受一個打開的文件作爲參數,你可以改變foo和寫入到:

proc foo {fp} { 
    puts $fp "some text" 
} 

set fp [open bar w] 
foo $fp 
close $fp 
5

如果你不能改變你的代碼,以一個頻道的名字寫(最穩健解決方案),您可以使用技巧將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保存複印件)。

3

通常,我會推薦Donal Fellows在his answer中建議的stdout重定向。

有時候這可能是不可能的。也許Tcl解釋器被鏈接到一個複雜的應用程序中,該應用程序本身就是輸出應該到達的想法,然後你不知道如何恢復stdout通道。

在這些情況下,您可以嘗試重新定義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在更復雜的應用。也許這也是鼓舞人心的。

3

這應該工作:

% 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 
% 
0

要做到這一點,我的調用包裝到我的Tcl PROC在shell腳本。這對Unix工作,不知道其他操作系統。

文件 - foo.tcl:

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

文件 - foo.csh(任何shell腳本會工作,我使用csh這個例子): enter code here

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

文件 - 主。TCL:

exec foo.csh > ./myoutput.txt

當然這些命令可以通過做像抓等安全措施包裹他們「花哨」 ......爲了清晰起見,我不包括他們,但我會建議他們使用。此外,我還包括$ argv,這是不需要的,因爲proc foo不需要參數,但是通常IRL會有參數。如果您只想附加到文件而不是覆蓋文件,請務必使用>>。

0

感謝分享CFI。 我想貢獻一下。 因此,我做了一些更改,重新定義轉儲放置到startlog上的文件,並在我們想要的時候結束對日誌文件的日誌記錄。 這將打印在stdout上,並將stdout重定向到文件。

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 
} 
0

我們可以用這種方式也

% 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 
嘗試
相關問題