And then catch the result on the command line into a file.
I have looked at the exec/open commands but they seem to open a file
rather than invoke linux commands. enlighten me pls.
I need this urgently. Any help is appreciated.
Please look up the 'file' command such as file mkdir, file rename, ...
exec/open do more than open files. I would look at the wiki for more
details:
http://wiki.tcl.tk/1039
http://wiki.tcl.tk/1241
Also, check to see if there is already a built-in command (as Hai Vu
suggested) first, before using exec and open. Also check tcllib.
> How to use tcl to perform linux commands?
Well, to actually perform the commands, there are at least 2 methods -
the exec command or Tcl's ability to open a pipe to a command (read
the open man page).
>What i mean is I want to
> write a tcl script that once executed it's able to lets say perfoms
> linux commands like:
> mkdir temp
> mv file1 file2
>
> And then catch the result on the command line into a file.
You would want to use a Tcl command like gets to get your input, write
the text of the command out to your file, invoke a pipe that routes
the stdout back to your tcl command, then write the output out to your
file.
>
> I have looked at the exec/open commands but they seem to open a file
> rather than invoke linux commands. enlighten me pls.
>
In the reference information for open < http://wiki.tcl.tk/open > ,
read about "COMMAND PIPELINES".
Be sure to read up on handing both stdout AND stderr, so that you
handle the case where the command you execute fails.
Also, don't forget to fflush the output to the file after each write,
so that in case of a crash, as much output as possible is in your log
file.
As others have mentioned, these kinds of tasks can be accomplished in
pure Tcl via [file mkdir] and [file rename]. If you really want to do
exactly what you asked for, then something like the following:
exec mkdir temp >>& mylog.txt
exec mv file1 file2 >>& mylog.txt
-- Neil
Thank you very much for your reply.
those mkdir and mv command I stated above are just examples I wanted
to do in linux. Infact I want to use some Iperf commands.
I found out how to do it using exec and open. Now I face another
problems.
Since I use the iperl commands in a loop and each command takes some
times to complete. Hence I need to use the & symbol after each
command to make to execute in parallel and then log the result into a
log file. But the results are displayed on the screen (command line)
and not get logged. Some weird number are logged instead.
Here is the code:
-------------------------------------------------------------------------------
if [catch {open ./log.txt w} io ] {puts "Problem in creating/opening a
file"}
for {set i 1} {$i<5} {incr i} {
put $io [exec iperf -c 192.1.1.1 -B 192.1.1.2$i &]
}
close $io
-------------------------------------------------------------------------------
And the log file log.txt:
3245
1235
1456
2541
Do you know how to tackle this: log all the results on the screen to
the log file log.txt. I think the problem lie on the & symbol. But I
need to execute commands all together at once.
Does the coding style (the way creating log file) is appropriate for
this purpose?
Thank you very much
> Since I use the iperl commands in a loop and each command takes some
> times to complete. Hence I need to use the & symbol after each
> command to make to execute in parallel and then log the result into a
> log file. But the results are displayed on the screen (command line)
> and not get logged. Some weird number are logged instead.
>
> put $io [exec iperf -c 192.1.1.1 -B 192.1.1.2$i &]}
When you think about it, it is bovious that Tcl can *either*
launch the program without waiting *or* wait for its output, but
not both. What exec returns immediately is the process id number
of the detached command. (You can refer to those if you want to
check whether the process has completed.)
What you want is to pipe the output directly to the file without
returning it to the Tcl script:
# Start fresh:
file delete ./log.txt
#
for {set i 1} {$i<5} {incr i} {
exec iperf -c 192.1.1.1 -B 192.1.1.2$i >> ./log.txt &
}
This may or may not give you problems due to output from
different concurrent executions getting mixed together,
depending on the size and form of the output, on the os
file handling, and on my blissful ignorance.
Donald Arseneau
And in fact, it is highly likely that it will in fact give you the
problems Donald mentioned. You don't normally want to have multiple
processes appending to the same log file unless a) every line of
output from the processes is uniquely identified, so that you can tell
which line came from which command, and b) every process guarantees
that its output will appear as a complete line.
I've seen cases where 2 or more processes writing to the same file had
bits of output intermingled so that you couldn't even tell what came
from where.
What you might want to do is to have each process write out to its own
file, then, once all the processes finish, run a command to
concatenate all the process log files into one master log.
I use something like the following quite a lot, to run several things
in the background, without waiting for them to complete, but still
capturing the output (the example uses tcl8.6isms):
proc run {args} {
set cmd $args
lappend cmd 2>@1
set handle [open |$cmd r]
chan configure $handle -blocking 0
chan event $handle readable [list [info coroutine] output]
set afterid [after 30000 [list [info coroutine] timeout]]
set output ""
try {
while {1} {
lassign [yield] wakeup_reason
switch -- $wakeup_reason {
timeout {
puts "Got bored waiting for [pid $handle]"
throw close ""
}
output {
set chunk [chan read $handle]
if {[chan eof $handle]} {
throw close ""
}
append output $chunk
}
}
}
} trap close {} {
try {
chan configure $handle -blocking 1
chan close $handle
} trap {CHILDSTATUS} {errmsg options} {
lassign [dict get $options -errorcode] - pid code
puts "Child died with exit code $code"
} trap {CHILDKILLED} {errmsg options} {
lassign [dict get $options -errorcode] - pid sigName msg
puts "Child was killed with signal $sigName"
} on ok {} {
puts "Child died naturally, output:\n$output"
}
} finally {
after cancel $afterid
}
}
coroutine coro_[incr ::coroseq] run find /
# Do other stuff
puts "hello, world"
vwait ::forever
Sorry, ended up being more code than I expected
Cyan
Agreed, and I should have reiterated your instructions to learn
about command pipelines. The project can be accomplished using
[open "|..."] instead of [exec ...] for the launching and [fileevent]
for the collection of output. Then Tcl can write out the log
file in well-separated chunks.
Donald Arseneau