web-dev-qa-db-ja.com

stdoutをtclのファイルにリダイレクトするにはどうすればよいですか?

proc出力をtcl内のファイルにリダイレクトするにはどうすればよいですか。たとえば、proc fooがあり、foo出力をファイルバーにリダイレクトしたい場合です。しかし、この結果を得ました

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

書き込むチャネルの名前を取得するようにコードを変更できない場合(最も堅牢なソリューション)、トリックを使用してstdoutをファイルにリダイレクトできます:reopening

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 を使用しない限り)。

5
Donal Fellows

これは機能するはずです:

% 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
% 
5
YM Li

一般的に、Donal Fellowsが提案するstdoutリダイレクトをお勧めします 彼の答え

時々これは不可能かもしれません。たぶん、Tclインタープリターは、出力がどこに行くべきかという素晴らしいアイデアを持っている複雑なアプリケーションにリンクされていて、stdoutチャネルを復元する方法がわかりません。

そのような場合は、putsコマンドを再定義してみてください。これを行う方法のコード例を次に示します。プレーンTclでは、コマンドは 名前を変更 安全な名前に再定義し、目的の機能に応じて、元のコマンドを安全な名前で呼び出すラッパーprocを作成することもできます。

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には別の より複雑なアプリケーションでputsを再定義する興味深い例 があります。多分これも刺激的です。

3
cfi

この方法でも試すことができます

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

CFIを共有していただきありがとうございます。私も貢献したいと思います。そのため、必要に応じて、startlogのファイルへのダンプの配置を再定義し、endlogのファイルへのロギングを終了するようにいくつかの変更を加えました。これにより、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
Sat

現在、foo > barと入力すると、Tclは2つのパラメーターを受け取るfoo procを実行しようとしています。これは存在しないため、エラーメッセージが表示されます。この問題に取り組むには2つの方法が考えられます。

トップレベルでリダイレクトできるので、tclsh tclsh > barを実行すると、すべての出力がリダイレクトされますが、これが目的であるとは思えません。

Fooを変更して、開いているファイルをパラメーターとして受け入れ、それに書き込むことができます。

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

set fp [open bar w]
foo $fp
close $fp
0
Jackson

これを実現するために、Tclprocへの呼び出しをシェルスクリプトでラップしました。これはUNIXで機能しますが、他のOSについてはよくわかりません。

ファイル-foo.tcl:

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

file-foo.csh(任意のシェルスクリプトが機能します。この例ではcshを使用しています):enter code here

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

ファイル-main.tcl:

exec foo.csh> ./myoutput.txt

もちろん、これらのコマンドは、キャッチなどの安全対策でラップすることで「ファンシー」にすることができます...わかりやすくするために、これらのコマンドは含めませんでしたが、使用することをお勧めします。また、proc fooはargsを受け取らないため、必要のない$ argvを含めましたが、通常、IRLにはargsがあります。ファイルを上書きするのではなく、単にファイルに追加する場合は、必ず>>を使用してください。

0
user3569602