In windows I have a batch file, named the same as a folder in its current directory.
I am trying to recursively launch a specific .exe
file that is a few folders deep in the above mentioned folder.
I am trying:
set "NAME=DRAGON QUEST XI S.exe"
for /R "%~n0\" %%I in ("%NAME%") do if exist "%%I" start "" /WAIT "%%I"
But that is trying to launch DRAGON.exe
, then QUEST.exe
, then XI.exe
then S.exe
and I don't understand why.
I think it will have something to do with quotes, but have tried adding/removing them from everywhere I could see and no luck.
Adding a wildcard to ("%NAME%*")
works, but could be troublesome if there is more than one .exe
that starts with DRAGON
.
CodePudding user response:
What you have encountered is caused by something that I consider a terrible design flaw of the for /R
loop and expansion of its meta-variable together with the ~
-modifiers.
Create the following batch file and execute it:
@for /R "%~dp0." %%I in (foo bar "foo bar" "foo bar?") do @(
echo/
echo Modifier '~nx': %%~nxI
echo No modifiers : %%I
echo Modifier '~' : %%~I
echo Modifier '~f' : %%~fI
echo '~' and quoted: "%%~I"
)
The output will be this, given that there are two files foo bar
and foo barS
available in the directory of the batch file:
Modifier '~nx': foo No modifiers : D:\test dir\foo Modifier '~' : D:\test dir\foo Modifier '~f' : D:\test dir\foo '~' and quoted: "D:\test dir\foo" Modifier '~nx': bar No modifiers : D:\test dir\bar Modifier '~' : D:\test dir\bar Modifier '~f' : D:\test dir\bar '~' and quoted: "D:\test dir\bar" Modifier '~nx': "foo bar" No modifiers : D:\test dir\"foo bar" Modifier '~' : D:\test dir\"foo bar" Modifier '~f' : D:\test dir\"foo bar" '~' and quoted: "D:\test dir\"foo bar"" Modifier '~nx': foo bar No modifiers : D:\test dir\foo bar Modifier '~' : D:\test dir\foo bar Modifier '~f' : D:\test dir\foo bar '~' and quoted: "D:\test dir\foo bar" Modifier '~nx': foo barS No modifiers : D:\test dir\foo barS Modifier '~' : D:\test dir\foo barS Modifier '~f' : D:\test dir\foo barS '~' and quoted: "D:\test dir\foo barS"
It seems that the ~
-modifiers (which remove potential surrounding quotation marks) are applied too late, namely after preceding an iterated item with the absolute root path. A standard for
loop does not precede anything, so the problem cannot arise and the ~
-modifiers may see a quoted string (remove /R "%~dp0."
from the batch file, run it again from its parent directory and check quotation in the output).
The line that reflects our situation is the one '~' and quoted: "D:\test dir\"foo bar""
; due to its wrong quotation, the command parser unintentionally recognises two different tokens "D:\test dir\"foo
and bar""
in the expanded value of "%%~I"
.
To return to your code, there are the following options to work around the bad behaviour of for /R
:
Append a wildcard (best to use
?
since it matches just a single character and therefore reduces the chance of matching unwanted items) and then recheck the name of the iterated item:set "NAME=DRAGON QUEST XI S.exe" for /R "%~n0" %%I in ("%NAME%?") do ( if /I "%%~nxI"=="%NAME%" ( if exist "%%I" ( ECHO start "" /WAIT "%%I" ) ) )
Let
dir /S
return the matching file(s) and usefor /F
to process its output:set "NAME=DRAGON QUEST XI S.exe" for /F "delims=" %%I in ('dir /S /B /A:-D-H-S "%~n0\%NAME%"') do ( if exist "%%I" ( ECHO start "" /WAIT "%%I" ) )