Arjen Markus I read a question the other day on c.l.t. about tracing a script and I replied to a reply from Larry Virden, but while I misunderstood the question and his answer, I kept thinking "what does ksh -x actually do?" Then the light went on and I realised what I should have done, come up with a small script like the one below.
While it is far from perfect (I have one script that seems to get stuck with it), it is a beginning. For the moment: here it is "as is". Maybe I will be able to perfect it later:
# trace_script.tcl -- # Trace a script that is being executed # Usage: # tclsh trace_script.tcl script-to-run args # # namespace Trace -- # Private namespace # namespace eval ::Trace { variable traceOut stdout } # prepareLine -- # Prepare the line of code for output # # Arguments: # line Line of code # Result: # Line of code with [ and ] escaped # proc ::Trace::prepareLine {line} { string map {[ \\\[ ] \\\] \" \\\" \{ \\\{ \} \\\} } $line } # source -- # Redefine the source command to manipulate the source # of the script # # Arguments: # filename Name of the file to be sourced # Result: # Whatever the source file does # Side effects: # The manipulated source file is loaded # if {[info commands ::tcl::source] == {}} then { rename source ::tcl::source } proc source {filename} { set infile [open $filename "r"] set outfile [open TMP_$filename "w"] while { [gets $infile line] >=0 } { puts $outfile "puts \$::Trace::traceOut \"[::Trace::prepareLine $line]\"" puts $outfile $line } close $infile close $outfile ::tcl::source TMP_$filename file delete -force TMP_$filename } # main -- # Prepare argv and source the code # namespace import catch { console show } set filename [lindex $argv 0] set argv [lrange $argv 1 end] source $filename
MSW says, nice :) I've taken the freedom to change the target of the rename to ::tcl::source and remove the temporary file later.
RS: Writing a temporary file isn't necessary - just collect the "instrumented" code in a string variable and eval that. But I see a bigger danger: not every line contains a single command - sometimes it's less, or more. Consider
The putses will be inserted both inside the 'example' command, and in the 'data' block, probably both leading to unexpected behavior. Better use trace execution, it's built in - see Steppin' out