I ran into an "odd" (to me) problem while writing a batch file, and hope someone can explain why it does what it does... I had a batch file that built-up a moderately complex command-line, and I wanted it to echo what it had built to the screen before executing so that I could check that it had been built correctly. There are other ways I could have done this1, but for various reasons I tried something of the form:
for %%a in (echo "") do %%~a complicated-command-line-with-parameters
The thought being that it would run the do
part twice: once with %%a
set to echo
(displaying the command to the console) and once with it set to ""
: the expectation was that it would actually execute the command (using %%~a
would strip the double-quotes and all that would be left is the command itself). However, while the echo
worked, the command itself was not executed.
For a minimal replication, run the following from a command-prompt:
C:\>for %a in (echo "") do %~a dir
C:\>echo dir
dir
C:\> dir
As can be seen, it runs the echo
command fine, but it seems that the space in front of dir
prevents it from being executed.
Note, though, that manually running a command with a leading space is fine:
C:\> dir
Volume in drive C is OS
Volume Serial Number is A8BD-F861
...
and, were it somehow trying to run the command <space>dir
, then it (probably) would have complained of a missing command:
C:\>" dir"
'" dir"' is not recognized as an internal or external command,
operable program or batch file.
Question: The space between %~a
(which is an empty string) and the command to be run seems to be causing the whole line to be ignored... does anyone know why?
Note: It make no difference whether it is run from the command-prompt (as above) or from within a .BAT
file (after changing %a
to %%a
etc.). Nor does it make any difference whether the command-to-be-run is a built-in command (e.g. dir
as above) or a standalone program.
Further evidence that it is the space between %~a
and the command that is causing the problem comes from the "fix" that I found:
C:\>for %a in ("echo " "") do %~adir
C:\>echo dir
dir
C:\>dir
Volume in drive C is OS
Volume Serial Number is A8BD-F861
...
By adding the "separating space" to the "echo "
string inside the for
command, and removing it from the do
clause (...do %~adir
), the command works as I originally expected (although I dislike not having a space in front of the command).
After skimming the (somewhat daunting) top answer to the question How does the Windows Command Interpreter (CMD.EXE) parse scripts? that SomethingDark helpfully linked to, a cleaner alternative that seems to work is:
C:\>for %a in (echo call) do %~a dir
C:\>echo dir
dir
C:\>call dir
Volume in drive C is OS
Volume Serial Number is A8BD-F861
...
There are probably idiomatic situations where having the extra call
might affect something, but for the moment, it seems to work as desired.
1 I could have put @echo on
just before the line inside the batch file, but that also causes the prompt (e.g. C:\MyDirectory\SubDir>
) to be shown, which I didn't want. The other "standard fallback" is to just duplicate the line and stick echo
in front of the first copy, but then it's too easy for them to get out-of-sync!
SomethingDark already pointed to the explanation.
It's the command vs argument token splitting of a line.
In your case the command token is always %~a
this will be replaced later, but even when its empty, the parser will not reevaluate the command token.
With your fix, the dir command is always part of the command token.
But when echo is prefixed it can still echo the remaining part.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With