2011-12-16 12 views
7

Bir proc çıktısını tcl'deki bir dosyaya nasıl yeniden yönlendirebilirim, örneğin bir proc foo'm var ve foo çıkışını bir dosya çubuğuna yeniden yönlendirmek istiyorum. Bu hata mesajını alıyorsanız yok olarak foo > bar Tcl, 2 parametre alır bir foo proc çalıştırmak için çalışıyor yazarken Fakat Şu anda bu sonucuStdout'u tcl içinde bir dosyaya nasıl yeniden yönlendirebilirim?

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

cevap

0

aldık. Bu sorunu çözebilmenin iki yolunu düşünebilirim.

En üst düzeyde yeniden yönlendirebilirsiniz, böylece tclsh tclsh > bar'u çalıştırdığınızda tüm çıktılar yeniden yönlendirilir, ancak bunun istediğiniz şey olduğundan şüpheliyim.

Bunu bir parametre olarak açık bir dosyayı kabul etmesi için foo değiştirmek ve buna yazabilirsiniz: Eğer (en sağlam yazmak için bir kanalın adını almak için kodunuzu değiştiremiyorsanız

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

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

çözüm), stdout dosyasını bir dosyaya yeniden yönlendirmek için bir numara kullanabilirsiniz: yeniden açılıyor.

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: 

Bunu yaparsanız, (bir kopyasını kaydetmek için TclX en dup kullanmazsanız) başlangıçtaki stdout yönlendirildi nerede kaybetmeyecek unutmayın.

3

Genellikle, Donal Fellows'ın his answer'da önerdiği stdout yönlendirmesini öneririm.

Bazen bu mümkün olmayabilir. Belki de Tcl yorumlayıcısı, çıktının nereye gitmesi gerektiğine dair mükemmel bir fikri olan karmaşık bir uygulamaya bağlanmıştır ve sonra stdout kanalını nasıl geri yükleyeceğinizi bilmiyorsunuzdur.

Bu gibi durumlarda, puts komutunu yeniden tanımlamayı deneyebilirsiniz. İşte bunu nasıl yapabileceğinize dair bir kod örneği. Düz Tcl'de, bir komut, renaming tarafından güvenli bir adla yeniden tanımlanabilir ve istenen işleve bağlı olarak, orijinal komutunu güvenli adda veya hiç bir şekilde çağırmayan bir sarıcı proc oluşturulabilir.

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 
} 

Ayrıca bir değişkene metin yönlendirebilirsiniz:

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 daha karmaşık uygulamalarda başka interesting example of redefining puts sahiptir. Belki bu da ilham verici.

3

Bu çalışması gerekir:

% 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

Ben bir kabuk içinde benim Tcl proc çağrıyı sarılı Bunu gerçekleştirmek için. Bu, diğer işletim sistemi hakkında emin değilim, unix üzerinde çalışır.

dosyası - foo.tcl:

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

dosyası - foo.csh (herhangi bir kabuk komut dosyası, bu örneğin csh kullanıyorum çalışır): enter code here

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

dosyası - Ana.tcl: Bu komutlar netlik uğruna onları içermiyordu, ama onların kullanımını öneriyoruz ... catch, vb gibi güvenlik önlemleri onları sararak 'fantezi' yapılabilir Elbette

exec foo.csh > ./myoutput.txt

. Ayrıca, proc foo'nun arga almaması nedeniyle gerekli olmayan $ argv'yi de ekledim, ancak tipik olarak IRL'de hatalar olacak. Dosyanın üzerine yazmak yerine dosyaya eklemek istiyorsanız >> kullandığınızdan emin olun.

0

CFI'yi paylaştığınız için teşekkür ederiz. Ben de katkıda bulunmak istiyorum. Yani, başlangıçta dosyaya döküm dökümü yeniden tanımlamak ve istediğimiz zaman dosyaya endlogta oturum açma sonlandırmak için bazı değişiklikler yaptım. Bu, stdout üzerine yazdıracak ve ayrıca stdout'u dosyaya yönlendirecektir.

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

Biz de bu şekilde

% 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 
yılında deneyebilirsiniz
İlgili konular