如何在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"
如何在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"
目前。我可以想到解決這個問題的兩種方法。
你可以在頂層重定向,所以當你運行tclsh tclsh > bar
時,所有的輸出都會被重定向,但是我懷疑這是你想要的。
,使其接受一個打開的文件作爲參數,你可以改變foo和寫入到:
proc foo {fp} {
puts $fp "some text"
}
set fp [open bar w]
foo $fp
close $fp
如果你不能改變你的代碼,以一個頻道的名字寫(最穩健解決方案),您可以使用技巧將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
保存複印件)。
通常,我會推薦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
在更復雜的應用。也許這也是鼓舞人心的。
這應該工作:
% 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
%
要做到這一點,我的調用包裝到我的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會有參數。如果您只想附加到文件而不是覆蓋文件,請務必使用>>。
感謝分享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
}
我們可以用這種方式也
% 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
嘗試