2011-12-16 11 views
7

cómo puedo redirigir una salida de proc a un archivo en tcl, por ejemplo, tengo un proc foo y me gustaría redirigir la salida foo a una barra de archivos. Pero obtuvo este resultado¿Cómo puedo redireccionar stdout a un archivo en tcl

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

Respuesta

0

En la actualidad cuando se escribe foo > bar Tcl está tratando de ejecutar un proc foo que toma 2 parámetros, ya que no existe obtiene el mensaje de error. Puedo pensar en dos formas en que puedes abordar este problema.

Puede redirigir al nivel superior, de modo que cuando ejecute tclsh tclsh > bar, toda la salida será redirigida, sin embargo, dudo que esto sea lo que desea.

podría cambiar foo para que acepte un archivo abierto como un parámetro y escribir a eso:

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

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

Si no puede cambiar el código para tomar el nombre de un canal a escribir (el más robusto solución), puede usar un truco para redirigir stdout a un archivo: reabriendo.

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: 

en cuenta que si usted hace esto, se pierde la pista de donde su inicial stdout fue dirigido a (a menos que utilice TclX de dup para guardar una copia).

3

En general, recomendaría la redirección estándar que sugiere Donal Fellows en his answer.

A veces esto no es posible. Tal vez el intérprete Tcl está vinculado a una aplicación compleja que tiene una idea elegante de hacia dónde debe ir el resultado, y luego usted no sabe cómo restaurar el canal stdout.

En esos casos, puede intentar redefinir el comando puts. Aquí hay un ejemplo de código sobre cómo puedes hacer eso. En Tcl simple, un comando puede ser redefinido por renaming en un nombre seguro, y creando un proceso de envoltura que llama al comando original con el nombre seguro - o no funciona en absoluto, dependiendo de la funcionalidad deseada.

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 
} 

También puede redirigir el texto en una variable:

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 
} 

El Tcl'ers Wiki tiene otra interesting example of redefining puts en aplicaciones más complejas. Quizás esto es inspirador también.

3

Esto debería funcionar:

% 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

Para lograr esto envolví la llamada a mi proc Tcl en un script de shell. Esto funciona en Unix, no estoy seguro acerca de otros sistemas operativos.

archivo - foo.tcl:

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

archivo - foo.csh (cualquier secuencia de comandos shell va a funcionar, estoy usando CSH para este ejemplo): enter code here

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

archivo - principal.TCL:

exec foo.csh > ./myoutput.txt

Por supuesto, estos comandos se pueden hacer 'fantasía' envolviéndolos en medidas de seguridad como la captura, etc ... para una mayor claridad no incluí ellos, pero yo recomendaría su uso. También incluí $ argv que no es necesario ya que proc foo no toma argumentos, pero típicamente IRL habrá argumentos. Asegúrese de utilizar >> si solo desea agregar al archivo en lugar de sobrescribirlo.

0

Gracias por compartir CFI. Me gustaría contribuir también. así que hice algunos cambios para redefinir puts on dump en file en startlog y finalizar el registro en endlog en el archivo cuando queramos. Esto se imprimirá en stdout y también redirigirá stdout al archivo.

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

Podemos tratar de esta manera también

% 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 
Cuestiones relacionadas