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 /Sreturn the matching file(s) and usefor /Fto 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" ) )
