windowscmdescaping

Windows cmd: Escape percent variable with spaces in filename impossible?


In Windows command line, how can I properly escape such a filepath? One that has spaces, percents, and variables in its filename such as %cd% and %errorlevel% without expanding the variables? Is this possible?

For example, run C:\Users\the impossible %cd% filepath.exe

I've looked and tried all around for percent escaping and quote escaping. Without variables in the filename, it does work. However if the filename contains percents with variables such as %cd% or %errorlevel% nothing appears to work at all, no matter any escape sequence.

Things I have tried:

"C:\Users\the impossible %cd% filepath.exe"

"C:\Users\the impossible %%cd%% filepath.exe"

"C:\Users\the impossible ^%cd^% filepath.exe"


Solution

  • In the command line context, there are different escaping rules than in a batch file.
    In command line context it's not possible to escape an percent sign, but there is a way to apparently escape it

    So in your case you can use:

    ^"C:\Users\the^ impossible^ %cd^%^ filepath.exe^"
    

    To be able to use the caret in the filename, the quotation marks must be escaped.

    But the caret sign can not really escape the percentage sign in %cd^% The parser tries to find a variable called cd^, if there is no such variable it simply removes the caret and the text remains untouched.
    The carets before the spaces are necessary to keep the file name together.

    But if such a variable exists, the command will fail:

    set "cd^=FAIL"
    

    There exists a second variant, which can escape single percent signs

    for /F "tokens=1-31" %%= in ("1") do "C:\Users\the impossible %%=cd%%= filepath.exe"
    

    A single percent sign is escaped by converting it to %%=

    It works as the first percent sign simply stays where it is, but the %= expands to nothing.
    In one of the batch parser phases the parser tries to expand %=cd%, but a variable can't start with a equal sign, so it's harmless.
    This variant is bulletproof, no predefined variable can disrupt it.

    This technique can be adapted to require only a single %= to escape a %

    for /F "tokens=1-31 delims==" %%= in ("1=2=3=4=5=6=7=8=9=0=1=2=3=4=5=6=7=8=9=0=1=2=3=4=%=6=7") do (
      echo "%=cd%=cd expands to '%cd%' special chars aren't a problem &<>|"
      "C:\Users\the impossible %=cd%= filepath.exe"
    )