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
example with a long line that we want to continue \ on the next line set data { red green blue }
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