Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

bat file execution

175 views
Skip to first unread message

Jacob

unread,
Feb 20, 2024, 2:49:56 PMFeb 20
to
Hello,

I am trying to execute a bat file that takes in a few arguments. From
Windows command line, this works as intended:

>"C:\Program Files\test.bat" "C:\Program Files\runFile.txt" 8

The tcl code looks like this:

set batFile {C:/Program Files/test.bat}
set runFile {C:/Program Files/runFile.txt}
set N 8
set command [concat \"$batFile\" \"$runFile\" $N]
exec {*}$command


Unless I'm missing something, this same process works fine for exe
files. With the batch file, it appears to fail due to the spaces in the
batch filepath. Any suggestions? I see online some suggestions to use
auto_execok but I can't really figure out how to apply it in this scenario.

Thanks,

Jacob

saitology9

unread,
Feb 20, 2024, 3:17:46 PMFeb 20
to
On 2/20/2024 2:49 PM, Jacob wrote:
>
> set batFile {C:/Program Files/test.bat}
> set runFile {C:/Program Files/runFile.txt}
> set N 8
> set command [concat \"$batFile\" \"$runFile\" $N]
> exec {*}$command
>

Concat flattens the arguments you provide, and when the exec gets it, it
looks for the first item as command name, which would be C:/Program.

You want to try this instead:

set command [list \"$batFile\" \"$runFile\" $N]

Jacob

unread,
Feb 20, 2024, 3:27:51 PMFeb 20
to
Thanks for your suggestion. I actually have tried that as well, and get
the following error:

couldn't execute ""C:/Program Files/test.bat"": No error

Anonymous

unread,
Feb 20, 2024, 4:33:51 PMFeb 20
to
The quotes are unnecessary. Remove them.

et99

unread,
Feb 20, 2024, 6:55:19 PMFeb 20
to
The problem appears to be when you have spaces in the path to the first parameter (the file to run/execute).

I can get it to work, but only by doing a

cd [file dirname $batFile]

and then only using the filename portion of batFile on the command line.

I believe this is likely a problem with [exec] as I recall a prior discussion on this a few years back.



et99

unread,
Feb 20, 2024, 8:32:18 PMFeb 20
to
Oh, forgot to show how I did the exec, so...

set command [list [file tail $batFile ] $runFile $N]
cd [file dirname $batFile]
exec cmd.exe /c {*}$command


Rich

unread,
Feb 20, 2024, 9:44:22 PMFeb 20
to
et99 showed the way to "run" a bat file on windows.

The reason you are having trouble is that windows has no notion of
"script" files like Unix/Linux systems do (i.e., there is nothing
equivalent to the #!/path/to/interpreter feature of Unix/Linux in
windows)

So you either have to launch the proper interpreter, passing it the bat
file as a parameter (as et99 showed) or you have to use auto_execok to
obtain the right "invocation" to run the batch file (and auto_execok
should give back something similar to what et99 showed).

On Unix/Linux systems script files are first class "executables" just
the same as an ELF binary executable for the host CPU. Under windows,
script files (and bat files) are truly second class citizens, at best.

et99

unread,
Feb 21, 2024, 1:03:18 AMFeb 21
to
A (lucky) google hit showed how it can actually be done w/o using the [cd], like this:

exec {*}[auto_execok start] {} /D [file dirname $batFile] [file tail $batFile] $runFile $N



To see what this expands to, I also dup'd this line changing exec to foo, with:
proc foo args {puts |$args|}
and get this result:

|C:/Windows/System32/cmd.exe /c start {} /D {C:/Users/et/Desktop/New folder} test.bat {C:/Users/et/Desktop/New folder/New Text Document.txt} 8|

The really strange thing is what this eventually results in (as reported in windows process explorer):

C:\WINDOWS\system32\cmd.exe /c ""C:\Users\et\Desktop\New folder\test.bat" "C:/Users/et/Desktop/New folder/New Text Document.txt" 8"


When it runs, it's set to the directory following the /D And yes, that is actually a pair of d-quotes around the whole shebang. I can't tell what part of that [exec] played, other than it's likely that it changed the forward / to \.


Ahhh the mysteries of windows :)


Jacob

unread,
Feb 21, 2024, 10:03:07 AMFeb 21
to
On 2/20/2024 10:03 PM, et99 wrote:
> exec {*}[auto_execok start] {} /D [file dirname $batFile] [file tail
> $batFile] $runFile $N

Thank you for your responses. This method does in fact work. It is
definitely more complicated than I would like. I explored solutions in
Python (subprocess.Popen) and Matlab (system) and they are much cleaner.
Perhaps they just have the same stuff already being done behind the scenes.

Harald Oehlmann

unread,
Feb 21, 2024, 11:17:19 AMFeb 21
to
IMHO, the following should do the job:

exec {*}[auto_execok start] "" [file nativename $batFile] [file
nativename $runFile] $N

Remark the empty pair of quotes as first argument of the start.exe
command. This is to avoid, that the batfile name is taken as window title.

Try "help start" in a dos box.

Remark also, that there are a couple of bugs here and 8.6.14 will again
change the behaviour.

Take care,
Harald


Ralf Fassel

unread,
Feb 21, 2024, 11:58:51 AMFeb 21
to
* Jacob <JacobL...@clevelandgolf.com>
| I am trying to execute a bat file that takes in a few arguments. From
| Windows command line, this works as intended:
>
| >"C:\Program Files\test.bat" "C:\Program Files\runFile.txt" 8
>
| The tcl code looks like this:
>
| set batFile {C:/Program Files/test.bat}
| set runFile {C:/Program Files/runFile.txt}
| set N 8
| set command [concat \"$batFile\" \"$runFile\" $N]
| exec {*}$command
>
>
| Unless I'm missing something, this same process works fine for exe
| files. With the batch file, it appears to fail due to the spaces in
| the batch filepath. Any suggestions?

IMHO you should just use [list] instead of [concat] to construct the
command and exec the .bat command directly, not via auto_execok, which
only introduces more quoting issues.

This works for me:

set batFile {C:/Program Files/test.bat}
set runFile {C:/Program Files/runFile.txt}
set N 8
set command [list $batFile $runFile $N]
exec {*}$command

TCL on Windows can 'exec' .bat files just fine (cf. TCL source code).

HTH
R'

Jacob

unread,
Feb 21, 2024, 1:39:31 PMFeb 21
to
Ralf,

This was actually the very first thing I tried. After troubleshooting a
bit more, it appears to fail when there is a space in $runFile.

-Jacob

Jacob

unread,
Feb 21, 2024, 1:46:36 PMFeb 21
to
Harald,

Thanks for the suggestion. It does not work for me. It opens up the
command prompt, but appears to fail due to the spaces in the filepath.

-Jacob

greg

unread,
Feb 21, 2024, 2:37:27 PMFeb 21
to
Am 20.02.24 um 20:49 schrieb Jacob:
#! /usr/bin/env tclsh
set batFile "C:/Program Files/test.bat"
set runFile "C:/Program Files/runFile.txt"
set N 8
exec cmd /c start /min "" $batFile $runFile $N

et99

unread,
Feb 21, 2024, 2:48:23 PMFeb 21
to
Jacob:

Are you certain its the space in runFile? When I try with a batFile that has no spaces in the path, it works even if runFile has spaces. When batFile has the spaces is when all the previously suggested solutions failed for me.

I tried with several versions of tcl, including an 8.6.9 tclkit, 8.6.13 magicsplat, and 9.0b1 all 3 give the same error, which is not coming from tcl source code, but is the same exact text as this from a cmd window (and has the back slashes regardless of how I sent them to exec):

C:\>cmd.exe /c C:\Program Files\test.bat
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

which is because there's no quotes around the file name. So, somewhere in the translation, [exec] has stripped them before sending them in. That is why it works if there are no spaces in the path.

Also, all that auto_execok does is look at the first parameter, which is "start" and generates:


% auto_execok start
C:/Windows/System32/cmd.exe /c start

where (from looking at it's code) it uses:

% set env(COMSPEC)
C:\WINDOWS\system32\cmd.exe
% file attributes $env(COMSPEC) -shortname
C:/Windows/System32/cmd.exe


et99

unread,
Feb 21, 2024, 3:58:31 PMFeb 21
to
Greg:

This doesn't work for me. It just hangs w/o running my batch file. I have to manually kill the processes (cmd and conhost). The command line that is ultimately generated will error out if typed into a cmd window.

The solution, as found here:

https://stackoverflow.com/questions/6376113/how-do-i-use-spaces-in-the-command-prompt

describes what I saw when I used the /D parameter, i.e. quotes around quotes. It does not seem to scan like tcl would, rather it must simply be looking at the first and last char for a " and then strips the pair, as in,

[string range <string> 1 end-1 ]

And then it process what's left as the command to run plus it's args.


Jacob

unread,
Feb 21, 2024, 7:24:50 PMFeb 21
to
Yes, it is quite weird. It will work if batFile OR runFile contain no
spaces. If both have a space, it fails!

et99

unread,
Feb 21, 2024, 9:47:09 PMFeb 21
to
On 2/21/2024 4:24 PM, Jacob wrote:
> Yes, it is quite weird. It will work if batFile OR runFile contain no spaces. If both have a space, it fails!

I agree, weird.

BTW, you might find this useful, here's my little windows arg tester .bat file I used for this exercise.

It's a template for a droplet that I use often. You can run it via command line or drop icons on the batch file icon itself. I use the technique for such things as, clipboard copy a file's full path, linux-like touch, and several checksums. It does assume wish is known to windows, else you need the full path.


::if 0 {
start wish "%~f0" %*
@echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1
IF defined DOUBLECLICKED (
exit
) ELSE (
cmd /k
)
:: }
wm wi .
console show
console eval {wm geom . 146x13+128+128; wm protocol . WM_DELETE_WINDOW exit }
if {$argc > 0} {
puts "argc = |$argc| "
foreach arg $argv {
set type "-"
if { [file isdirectory $arg] } {
set type "D"
} elseif { [file readable $arg] } {
set type "F"
}
puts "arg [incr n] = $type |$arg| "
}
} else {
puts stderr "No arguments found"
}

Ralf Fassel

unread,
Feb 22, 2024, 5:20:22 AMFeb 22
to
* Jacob <JacobL...@clevelandgolf.com>
| On 2/21/2024 8:58 AM, Ralf Fassel wrote:
| > IMHO you should just use [list] instead of [concat] to construct the
| > command and exec the .bat command directly, not via auto_execok, which
| > only introduces more quoting issues.
| > This works for me:
| > set batFile {C:/Program Files/test.bat}
| > set runFile {C:/Program Files/runFile.txt}
| > set N 8
| > set command [list $batFile $runFile $N]
| > exec {*}$command
| > TCL on Windows can 'exec' .bat files just fine (cf. TCL source
| > code).
>
| Ralf,
>
| This was actually the very first thing I tried. After troubleshooting
| a bit more, it appears to fail when there is a space in $runFile.

Can you
- tell what 'fail' means in this context:
- TCL fails to execute the batch
- the batch fails to recognize the parameters
- other?

- show the contents of C:/Program Files/test.bat

- show the transcript of the session you tried?

Here's mine:

$ cd C:/Users/ralf/AppData/Local/Temp/foo bar

$ cat xxx.bat
@echo off
REM xxx.bat
echo this is xxx.bat
echo arguments /%1/ /%2/ /%3/

$ tclsh
% pwd
C:/Users/ralf/AppData/Local/Temp/foo bar
% set cmd [list [file join [pwd] xxx.bat] arg1 "arg2 with space" arg3]
{C:/Users/ralf/AppData/Local/Temp/foo bar/xxx.bat} arg1 {arg2 with space} arg3
% exec {*}$cmd
this is xxx.bat
arguments /arg1/ /"arg2 with space"/ /arg3/

HTH
R'

Jacob

unread,
Feb 22, 2024, 9:30:26 AMFeb 22
to
Ralf,

Sure, here is my bat file (test.bat):

@echo off
(for %%a in (%*) do (
echo %%a
))

I have placed the file in 2 locations:
"C:\batTest\bat test\test.bat"
"C:\batTest\test.bat"

I am running Tcl 8.6.13 via Magic Splat in tkcon shell.


(bin) 54 % #Test1:
set batFile {C:\batTest\bat test\test.bat}
set arg1 {argNoSpaces}
set arg2 8
set command [list $batFile $arg1 $arg2]
exec {*}$command

Output:
argNoSpaces
8


(bin) 59 % #Test2:
set batFile {C:\batTest\test.bat}
set arg1 {argNoSpaces}
set arg2 8
set command [list $batFile $arg1 $arg2]
exec {*}$command

Output:
argNoSpaces
8


(bin) 64 % #Test3:
set batFile {C:\batTest\test.bat}
set arg1 {arg with spaces}
set arg2 8
set command [list $batFile $arg1 $arg2]
exec {*}$command

Output:
"arg with spaces"
8


#Test4:
set batFile {C:\batTest\bat test\test.bat}
set arg1 {arg with spaces}
set arg2 8
set command [list $batFile $arg1 $arg2]
exec {*}$command

Output:
'C:\batTest\bat' is not recognized as an internal or external command,
operable program or batch file.


(bin) 89 % #Test5:
set batFile {C:\batTest\bat test\test.bat}
set arg1 {argNoSpace}
set arg2 {arg with spaces}
set command [list $batFile $arg1 $arg2]
exec {*}$command

Output:
'C:\batTest\bat' is not recognized as an internal or external command,
0 new messages