I have this batch file with command:
xyz.exe -parm1 path1/a.wav > path2/a.txt
How can this command be executed in TCL script, so that xyz.exe when called with arguments as parm1 and input path path1 of wav file a.wav, produces op that is redirected to a.text file in path2?
I have very basic TCL knowledge, but I couldn't find way of redirection.
sedy
Tcl's exec command knows how to redirect command output into a file. You can just do this:
exec xyz.exe -parm1 path1/a.wav > path2/a.txt
Got it working as below:
set ip_pth path1/a.wav
set op_pth path2/a.txt
set lf [open $op_pth w]
puts $lf [exec xyz.exe -parm1 $ip_pth]
close $lf
Related
I'm trying to checkout Joe English's tile-extras from Github using svn using a Tcl script.
The required command is
svn checkout https://github.com/jenglish/tile-extras.git path
I have some code that boils down to
exec C:/cygwin64/bin/svn.exe checkout \
https://github.com/jenglish/tile-extras.git C:/cygwin64/tmp/TCL61416]
which fails with the message
couldn't execute "C:\cygwin64\bin\svn.exe checkout
https:\github.com\jenglish\tile-extras.git
C:\cygwin64\tmp\TCL61416": No error
Pasting the command quoted in the error message into a Windows Command Prompt window, I see
svn: E125002: 'https:\github.com\jenglish\tile-extras.git' does not appear to be a URL
So, the problem seems to be that exec converts Tcl-style paths to Unix-style a little over-enthusiastically. Is there any way I can prevent it from converting https://github.com/jenglish... to https:\github.com\jenglish...?
For information, I'm running on Windows 10, with cygwin (setup version 2.889 (64 bit)), svn 1.9.7 and tcl version 8.6.7 (via ActiveTcl 8.6.7.0).
UPDATE
Here is my actual code, which I'm only slightly embarrassed by:
# svn wrapper proposed by Donal Fellows at
# http://stackoverflow/questions/49224268
proc svn {args} {
exec {*}[auto_execok svn] {*}$args <#stdin >#stdout }
# Checkout from github to a temporary repository
set repository https://github.com/jenglish/tile-extras.git set
svnImage [auto_execok svn]
set fil [file tempfile tempfnm] close $fil file delete $tempfnm
set tempRepo [file rootname $tempfnm] puts stdout tempRepo:\ $tempRepo
file mkdir $tempRepo
set svnCmd [list svn checkout $repository [file nativename $tempRepo]]
puts stdout svnCmd:\ $svnCmd eval $svnCmd
# Determine the tile-extras sources
set sourceFiles {keynav.tcl icons.tcl}
set targets [file nativename [file join $tempRepo trunk *.tcl]]
foreach filnam [split [svn ls $targets] \n] {
if {[string match *.tcl $filnam] && [lsearch $sourceFiles $filnam] < 0} {
lappend sourceFiles $filnam
}
}
And here is the result
$ tclsh foo.tcl
tempRepo: C:/cygwin64/tmp/TCL61838
svnCmd: svn checkout
https://github.com/jenglish/tile-extras.git {C:\cygwin64\tmp\TCL61838}
A C:\cygwin64\tmp\TCL61838/branches
A C:\cygwin64\tmp\TCL61838/trunk
A C:\cygwin64\tmp\TCL61838/trunk/README.md
A C:\cygwin64\tmp\TCL61838/trunk/dialog.tcl
A C:\cygwin64\tmp\TCL61838/trunk/doc
A C:\cygwin64\tmp\TCL61838/trunk/doc/dialog.n
A C:\cygwin64\tmp\TCL61838/trunk/doc/keynav.n
A C:\cygwin64\tmp\TCL61838/trunk/icons.tcl
A C:\cygwin64\tmp\TCL61838/trunk/keynav.tcl
A C:\cygwin64\tmp\TCL61838/trunk/license.terms
A C:\cygwin64\tmp\TCL61838/trunk/pkgIndex.tcl
Checked out revision 7.
svn: E155007: '/home/alan/C:\cygwin64\tmp\TCL61838\trunk\*.tcl' is not a working copy
while executing "exec {*}[auto_execok svn] {*}$args <#stdin >#stdout"
(procedure "svn" line 2)
invoked from within "svn ls $targets"
invoked from within "split [svn ls $targets] \n"
invoked from within "foreach filnam [split [svn ls $targets] \n] {
if {[string match *.tcl $filnam] && [lsearch $sourceFiles $filnam] < 0} {
lappend sourceFiles $filn..."
(file "foo.tcl" line 30)
$ ls /tmp/TCL61838/
$
The directory /tmp/TCL61838 is empty, so it seems the svn checkout command didn't complete completely happily. I also see an unpleasant mixture of forward slashes and backslashes being reported by svn.
Thanks in advance for any more help.
Given the error message, it looks like you're getting word boundaries wrong in the code that you've not shown us; while you might believe the code “boils down to” to that exec, it's not actually done that. Also, you've flipped the slashes in the URL which won't work, but that's probably a side-effect of something else.
Alas, I can't quite guess how to fix things for you. There's just too many options. I provide a suggestion below, but there's no telling for sure whether it will work out.
Diagnosis Methodology
The evidence for why I believe that the problem is what I say? This interactive session log (on OSX, but the generic behaviour should be the same):
% exec cat asdkfajh
cat: asdkfajh: No such file or directory
% exec "cat akjsdhfdkj"
couldn't execute "cat akjsdhfdkj": no such file or directory
% exec "cat aksdjhfkdf" skdjfghd
couldn't execute "cat aksdjhfkdf": no such file or directory
The first case shows an error from an external program. The second case shows an error due to no-such-program. The third case shows that arguments are not reported when erroring due to to no-such-program.
This lets me conclude that both C:\cygwin64\bin\svn.exe and its arguments (checkout, https:\github.com\jenglish\tile-extras.git and C:\cygwin64\tmp\TCL61416) were actually passed as a single argument to exec, a fairly common error, and that the problems lie in the preparatory code. You don't show us the preparatory code, so we can't truly fix things but we can make suggestions that address the common problems.
Suggested Approach
A good way to reduce these errors is to write a small wrapper procedure:
proc svn {args} {
# I add in the I/O redirections so svn can ask for a password
exec {*}[auto_execok svn] {*}$args <#stdin >#stdout
}
This would let you write your call to svn as:
svn checkout $theURL [file nativename $theDirectory]
and it would probably Just Work™. Also note that only the directory name goes through file nativename; the URL does not. (We could embed the call to file nativename in the procedure if we were making a specialised procedure to do checkouts, but there's too much variation in the full svn program to let us do that. The caller — you — has to deal with it.)
I am using TCL on a Windows 7 machine. And I need to invoke the Windows move command via exec. However I cannot get it to work.
I am aware that TCL has the file rename ability, but for reasons I cannot get into I'm being asked to use the Windows move CLI.
When I use the auto_execok with move, that command returns an empty string. I've also tried with the {*} but it never works.
% info tclversion
8.6
%
% move src dest
invalid command name "move"
%
% [auto_execok move] src dest
ambiguous command name "": after append apply array auto_execok auto_import auto _load auto_load_index auto_qualify binary break case catch cd chan clock close c oncat continue coroutine dict encoding eof error eval exec exit expr fblocked fc onfigure fcopy file fileevent flush for foreach format gets glob global history if incr info interp join lappend lassign lindex linsert list llength lmap load l range lrepeat lreplace lreverse lsearch lset lsort namespace open package pid pr oc puts pwd read regexp regsub rename return scan seek set socket source split s tring subst switch tailcall tclLog tell throw time trace try unknown unload unse t update uplevel upvar variable vwait while yield yieldto zlib
%
I've also looked at the contents of the auto_execok command using the info body auto_execok and it almost looks like they didn't add 'move' to the list of suported commands....
Any suggestions on how to interface with the Windows move command from a TCL program?
Is move built into cmd? You might try:
exec {*}[auto_execok cmd] /c move src dest
I don't have a windows box to test with right now.
I need to browse a URL using Internet Explorer, and close using taskkill through TCL script. I am using following TCL script for this.
My TCL Script:
set data [open input_url.txt r]
set test [read $data]
foreach url $test {
exec "C:/Program Files/Internet Explorer/IEXPLORE.EXE" $url
after 2000
exec "C:/WINDOWS/System32/taskkill.exe" /IM IEXPLORE.EXE /F
}
input_url.txt content:
clickshare upload.com upload.to 10upload.com 123upload.pl 139pan.com 163pan.com
But When I run this script, Browser with first URL is opened. But nothing is happening after this. After 2-3 minutes, if I close the browser manually, I am seeing the following error:
C:\Users\kumar\Desktop\test>tclsh stack_question.tcl
child process exited abnormally
while executing
"exec "C:/Program Files/Internet Explorer/IEXPLORE.EXE" $url"
("foreach" body line 2)
invoked from within
"foreach url $test {
exec "C:/Program Files/Internet Explorer/IEXPLORE.EXE" $url
after 2000
exec "C:/WINDOWS/System32/taskkill.exe" /IM IEXPLO..."
(file "stack_question.tcl" line 3)
C:\Users\kumar\Desktop\test>
I am able to kill the browser session manually using taskkill.exe as shown below:
C:\Users\kumar\Desktop\test>tclsh
% exec "C:/WINDOWS/System32/taskkill.exe" /IM IEXPLORE.EXE /F
SUCCESS: The process "iexplore.exe" with PID 3948 has been terminated.
SUCCESS: The process "iexplore.exe" with PID 3744 has been terminated.
%
Could any one please help me to fix this issue?
Thanks in advance.
It seems like exec is waiting for iexplore.exe to finish before it continues execution. In order to allow immediate return use start command:
exec cmd.exe /c start iexplore.exe $url
This will return immediately.
My problem is that I have been trying to run the following command on the shell.
set a [file mkdir ./Desktop/New]
set b [open $a/new.rpt w]
Hoping that a would reference the new folder
The interpreter does not return any error so I assumed that I could do this-->
set b [open $a/new.rpt w]
This time an error is displayed saying-->
couldn't open "/new.rpt": permission denied
Could someone please help me out here??
The result (on success) of file mkdir is an empty string. (On failure, you get an exception that you can catch or try … trap ….) To do what you want, put the value in the variable first:
set a ./Desktop/New
file mkdir $a
set b [open $a/new.rpt w]
You might want to do this at some point as well:
set a [file normalize $a]
This gets rid of the reference to the current directory and converts $a to be an absolute filename, which is useful if you're going to do cd /somewhere/else sometime.
I am running Tcl script for connecting Telnet port. For this script I want to store all the CMD output in a log file. how to do this in Tcl script? Script as below:
#!/usr/bin/expect -f
#!usr/bin/expect
package require Expect
spawn telnet $serverName $portNum
expect "TradeAggregator>"
send "Clients\r"
expect "Client:"
send "1\r"
expect "1-Client>"
send "Pollers\r"
expect "Client Pollers"
send "2\r"
send "n\r"
expect ">"
set passwordOption $expect_out(buffer)
set searchString "Not confirmed"
if {[string match *$searchString* $passwordOption]} {
puts "match found" }\
else {
puts "match not found"
xmlPasswordChange $polName
}
all the puts output and xmlPasswordChange procedure output is not printing in the log file. can you please point out where i am doing wrong.
Thanks for your help in advance.
You want to insert a log_file command where you want to start saving the output. For example, if you want to save all the output, then stick it to the beginning:
#!/usr/bin/expect -f
log_file myfile.log ;# <<< === append output to a file
package require Expect
spawn telnet $serverName $portNum
expect "TradeAggregator>"
send "Clients\r"
expect "Client:"
send "1\r"
expect "1-Client>"
send "Pollers\r"
expect "Client Pollers"
send "2\r"
Be default, log_file appends if the file exists, or create a new one. If you want to start a new log every time, then:
log_file -noappend myfile.log
Update
Per your question regarding why puts outputs go to the console and not the log file. The way I understand is puts will go to the console. If you want to log to the log file (open that was opened with the log_file command), then use the send_log command instead:
log_file -noappend myfile.log
send_log "This line goes into the log file"
send_user "This line goes into both the log file and console\n"
puts "This line goes to the console"
The above example introduced another command: send_user, which acts like puts and send_log combined. Note that send_user does not include a new line, so the caller should include it.
Also We can create our own log file by stranded [open $file_name w] command and keep writing everything to that file.