The question's title is very generic, which inevitably draws many readers looking for a generic solution.
By contrast, the OP's problem is exotic: needing to deal with an auto-generated batch file that is ill-formed and cannot be modified: %
signs are not properly escaped in it.
The accepted answer provides a clever solution to the specific - and exotic - problem, but is bound to create confusion with respect to the generic question.
If we focus on the generic question:
How do you use %
as a literal character in a batch file / on the command line?
Inside a batch file, always escape %
as %%
, whether in unquoted strings or not; the following yields My %USERNAME% is jdoe
, for instance:
echo My %%USERNAME%% is %USERNAME%
echo "My %%USERNAME%% is %USERNAME%"
On the command line (interactively) - as well as when using the shell-invoking functions of scripting languages - the behavior fundamentally differs from that inside batch files: technically, %
cannot be escaped there and there is no single workaround that works in all situations:
In unquoted strings, you can use the "^
name-disrupter" trick: for simplicity, place a ^
before every %
char, but note that you're not technically escaping %
that way (see below for more); e.g., the following again yields something like My %USERNAME% is jdoe
:
echo My ^%USERNAME^% is %USERNAME%
In double-quoted strings, you cannot escape %
at all, but there are workarounds:
You can use unquoted strings as above, which then requires you to additionally ^
-escape all other shell metacharacters, which is cumbersome; these metacharacters are: <space> & | < > "
Alternatively, unless you're invoking a batch file, , you can individually double-quote %
chars as part of a compound argument (most external programs and scripting engines parse a compound argument such as "%"USERNAME"%"
as verbatim string %USERNAME%
):
some_exe My "%"USERNAME"%" is %USERNAME%
From scripting languages, if you know you're calling a binary executable, you may be able to avoid the whole problem by forgoing the shell-invoking functions in favor of the "shell-free" variants, such as using execFileSync
instead of execSync
in Node.js.
Optional background information re command-line (interactive) use:
Tip of the hat to jeb for his help with this section.
On the command line (interactively), %
can technically not be escaped at all; while ^
is generally cmd.exe
's escape character, it does not apply to %
.
As stated, there is no solution for double-quoted strings, but there are workarounds for unquoted strings:
The reason that "^
name-disrupter" trick (something like ^%USERNAME^%
) works is:
It "disrupts" the variable name; that is, in the example above cmd.exe
looks for a variable named USERNAME^
, which (hopefully) doesn't exist.
On the command line - unlike in batch files - references to undefined variables are retained as-is.
Technically, a single ^
inside the variable name - anywhere inside it, as long as it's not next to another ^
- is sufficient, so that %USERNAME^%
, for instance, would be sufficient, but I suggest adopting the convention of methodically placing ^
before each and every %
for simplicity, because it also works for cases such as up 20^%
, where the disruption isn't even necessary, but is benign, so you can apply it methodically, without having to think about the specifics of the input string.
A ^
before an opening %
, while not necessary, is benign, because ^
escapes the very next character, whether that character needs escaping - or, in this case, can be escaped - or not. The net effect is that such ^
instances are ultimately removed from unquoted strings.
Largely hypothetical caveat: ^
is actually a legal character in variable names (see jeb's example in the comments); if your variable name ends with ^
, simply place the "disruptive" ^
somewhere else in the variable name, as long as it's not directly next to another ^
(as that would cause a ^
to appear in the resulting string).
That said, in the (very unlikely) event that your variable has a name such as ^b^
, you're out of luck.