3

私は制御できない tcl の手順を使用しています。次のような出力ウィンドウに多くの詳細が表示されます。

Response:<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><soapenv:Fault><faultcode>soapenv:Server</faultcode><faultstring>Item not valid: The specified Standard SIP1 Profile was not found</faultstring><detail><axlError><axlcode>5007</axlcode><axlmessage>Item not valid: The specified Standard SIP1 Profile was not found</axlmessage><request>updatePhone</request></axlError></detail></soapenv:Fault></soapenv:Body></soapenv:Envelope>

この stdout を変数にリダイレクトする方法はありますか? 私は tcl が初めてで、これを行う方法がわかりません。

4

6 に答える 6

7

Tcl 8.6 を使用している場合は、次の方法stdoutで適切な変換を追加することにより、すべての出力を にトラップできchan pushます。

# Use a class to simplify the capture code
oo::class create CapturingTransform {
    variable var
    constructor {varName} {
        # Make an alias from the instance variable to the global variable
        my eval [list upvar \#0 $varName var]
    }
    method initialize {handle mode} {
        if {$mode ne "write"} {error "can't handle reading"}
        return {finalize initialize write}
    }
    method finalize {handle} {
        # Do nothing, but mandatory that it exists
    }

    method write {handle bytes} {
        append var $bytes
        # Return the empty string, as we are swallowing the bytes
        return ""
    }
}

# Attach an instance of the capturing transform
set myBuffer ""
chan push stdout [CapturingTransform new myBuffer]

# ... call the problem code as normal ...

# Detach to return things to normal
chan pop stdout

注意事項: これは、チャネル上のすべての出力をキャプチャしますが、生成されます (スレッド間または出力が C レベルで生成される場所でも機能します)。これにより、チャネルの構成されたエンコーディングへの変換後にキャプチャが適用されるため、バイトが挿入されます。 myBuffer. また、8.6 が必要です。関連する API は、以前のバージョンではスクリプトに公開されていませんでした (ただし、C に相当するものは、SSL サポートなどの一部の拡張機能で使用されていました)。

于 2013-01-26T14:59:07.003 に答える
2

いつも同じ質問..

いくつかのオプションがあります:

  • Tcl_SetStdChannelスクリプト レベルに公開する Tcl 拡張機能を C で記述します。おそらくより良い解決策の 1 つですが、それほど簡単ではありません。

  • 名前を変更して置き換えputsます。これを要求されずに stdout に書き込むライブラリからのほとんどの出力で十分です。しかし、誰かが標準出力chan putsに何かを書き込む方法は他にもたくさんあります。チャンネルの使えるところを全部書き直すのは大変だと思います。fcopyexec echo foo >@stdout

  • interp から stdout を削除します。欠点は、出力が得られないことです。プロシージャの実行後、stdout を取得できます。例えば:

    set tint [interp create]
    interp transfer {} stdout $tint
    ... call your stuff here...
    interp share $tint stdout {}
    interp delete $int
    

    必要になるたびに interp を作成するべきではないことに注意してください。一度作成して再利用します。

于 2013-01-26T10:39:26.437 に答える
2

風変わりな回避策があります: を使用execしてスクリプトを 2 回目に呼び出し、出力をキャプチャします。簡単な例を次に示します。

#!/usr/bin/env tclsh

# How can I call a procedure, which produces stdout output, and capture
# stdout?

proc produce_output {} {
    puts "Goodbye Friday"
    puts "Hello, weekend"    
}

if {[lindex $::argv 0] == "-run"} {

    # If command line contains a special flag, run the procedure in
    # question
    produce_output

} else {

    # By default, we will run this script again, with a special flag
    # and capture the output

    set output [exec tclsh [info script] -run]
    puts "Output: >$output<"

}

スクリプトを 2 回実行するのは得策ではないため、この方法は風変わりです。たとえば、スクリプトの一部がいくつかのデータベース テーブルを更新する場合...

于 2013-01-27T03:30:02.597 に答える
0

「出力ウィンドウに...を置く」とはどういう意味かによって異なります。

「出力ウィンドウに...を置く」、つまりデータを印刷する場合、出力をキャプチャすることができます。

それが単にその値を生成し、他の手段で出力される場合は、@Eduが提案したことを実行してください。

于 2013-01-25T21:29:10.490 に答える
0
set output "[procedure_that_creates_the_output]"

角かっこで囲まれたものはすべてネストされたコマンドであり、評価され、その結果が外部コマンドで使用されます。したがって、上記では、プロシージャの出力が引用符の間に挿入されて文字列が作成され、出力変数に保存されます。

proc addition {x y} {                                                           
    return [expr $x+$y]                                                         
}                                                                               

set result [addition 2 3]                                                       
puts $result                                                                   

ここでは、最初に[addition 2 3]、xを2、yを3としてproc addを実行する値を解決します。これは、別のネストされた式で計算された合計を返し、その結果5は[addition 2 3]、外部スクリプトで置き換えられますset result 5

于 2013-01-25T21:29:33.593 に答える
0

tcl プロシージャが puts を使用して stdout に書き込んでいる場合は、puts を再定義するだけです。これをコーディングした後、入力変数をグローバルにする必要がある場合はさらに簡単になります。ただし、そのままでは、スタックフレームによって正しい変数が変更されます。

proc stdout2var { var } { 
    set level [ info level ]
    # we may have called stdout2var before so this allows only one variable at a time
    # and preserves tcls original puts in putsorig 
    if { [ string length [info commands "putsorig" ] ]  == 0 } { 
        rename ::puts ::putsorig
    } 
    eval [subst -nocommands {proc ::puts { args } { 
    set fd stdout 
    # args check 
    switch -exact -- [llength \$args ] {
        1 { 
        set fd stdout
        } 
        2 { 
        if { ![string equal \"-nonewline\" [lindex \$args 0 ] ] } {
            set fd [lindex \$args 0 ]
        }
        }
        3 {
        set fd [lindex \$args 1 ]
        }
        default { 
        error \"to many or too few args to puts must be at most 3 ( -nonewline fd message )\" 
        }
    }
    # only put stdout to the var 
    if { [string equal \"stdout\" \$fd ] } {
           # just level and var are subst 
        set message [lindex \$args end ]
        uplevel [expr { [info level ] - $level + 1 } ] set $var \\\"\$message\\\"
    } else {
        # otherwise evaluate with tcls puts 
        eval ::putsorig \$args 
    }
    } } ]
} 

proc restorestdout { } {
    # only do rename if putsorig exists incase restorestdout is call before stdout2var or 
    # if its called multiple times
    if {  [ string length [ info commands "putsorig"] ] != 0  } { 
    rename ::puts ""
    rename ::putsorig ::puts 
    } 
}

# so for some test code . because we cannot write to stdout we need to write to stderr. 
# puts on level 1 
proc myproc { a b } { 
    puts "$a $b " 
} 
# example with some deeper levels now puts is on level 2 
proc myUberProc { c } {
    myproc "a" $c
}
# this prints Ya Hoo to stdout
myproc "Ya" "Hoo"
set x ""
stdout2var x 
#puts "====\n[ info body putter ]\n===="
puts stdout " Hello" 
puts stderr "x = $x"; # x = Hello\n
puts -nonewline stdout " Hello" 
puts stderr "x = $x"; # x = Hello
myproc "Ya" "Hoo" 
puts stderr "x = $x" ; # x = Ya Hoo\n
set y "" 
stdout2var y
myUberProc "Zip"
puts stderr "y = $y , x = $x" ; # y = a Zip , x = Ya Hoo\n
restorestdout 
# now writes to stdout 
puts "y = $y , x = $x" ; # y = a Zip , x = Ya Hoo\n

出力は次のようになります。

Ya Hoo 
x =  Hello
x =  Hello
x = Ya Hoo 
y = a Zip  , x = Ya Hoo 
y = a Zip  , x = Ya Hoo 
于 2013-08-01T05:44:22.077 に答える