Ignore percent sign in batch file
Asked Answered
R

6

40

I have a batch file which moves files from one folder to another. The batch file is generated by another process.

Some of the files I need to move have the string "%20" in them:

move /y "\\myserver\myfolder\file%20name.txt" "\\myserver\otherfolder"

This fails as it tries to find a file with the name:

\\myserver\myfolder\file0name.txt

Is there any way to ignore %? I'm not able to alter the file generated to escape this, such as by doubling percent signs (%%), escaping with / or ^ (caret), etc.

Rile answered 15/12, 2009 at 12:20 Comment(3)
You should accept rud3y's answer insteadRunstadler
As I said, I'm not able to alter the file generated. I get the file with the % sign as: file%20name.txt. I can't add an extra % into it.Rile
Possible duplicate of Escape percent in bat fileHumanize
V
-3

You should be able to use a caret (^) to escape a percent sign.

Editor's note: The link is dead now; either way: It is % itself that escapes %, but only in batch files, not at the command prompt; ^ never escapes %, but at the command prompt it can be used indirectly to prevent variable expansion, in unquoted strings only.

The reason %2 is disappearing is that the batch file is substituting the second argument passed in, and your seem to not have a second argument. One way to work around that would be to actually try foo.bat ^%1 ^%2... so that when a %2 is encountered in a command, it is actually substituted with a literal %2.

Verney answered 15/12, 2009 at 12:24 Comment(4)
You can't escape a percent sign with a caret, only with a percent signFic
@Unrefined Technically you can't escape a percent sign on the command line. The only cause why it seems to work is that cmd.exe searches for the variable username^ in %username^%, so you can also use %user^name% it has nothing to do with escaping a percent. Btw foo.bat ^%1 ^%2 is useless at all, as the carets are simply removed after the %1 and %2 are expanded. See also How variables are expandedFic
As @Fic points out, ^ cannot actually escape %, despite generally acting as the escape character in unquoted strings. However, you can use ^ to effectively suppress variable expansion by placing it before, after, or inside the variable name, but that only works on the command line, not inside batch files. The rest of the answer provides a clever solution to the OP's very specific problem: needing to deal with an ill-formed, auto-generated batch file; this specificity of the OP's problem is at odds with how generic the title of the question is, which invites confusion.Unrefined
@jeb: Again, thanks for the clarification re escaping %. The ^ in ^%2 is useless here, but does no harm: the proposed solution works with both ^%2 and %2, because - as far as I know - an interactive cmd.exe shell never has parameters, and so a reference such as %2 is retained as is (treated as a literal; by contrast, you'd have to use %%2 when calling from another batch file). Using %^2 to be safe and explicit is also an option.Unrefined
S
63

You need to use %% in this case. Normally using a ^ (caret) would work, but for % signs you need to double up.

In the case of %%1 or %%i or echo.%%~dp1, because % indicates input either from a command or from a variable (when surrounded with %; %variable%)

To achieve what you need:

move /y "\\myserver\myfolder\file%%20name.txt" "\\myserver\otherfolder"

I hope this helps!

Seism answered 22/2, 2012 at 15:19 Comment(2)
Note that %% only works within a batch file and not within the command prompt itself. On the command prompt itself, a caret will escape a percent sign ^% displays a %.Osteen
@MichaelPlautz: Good point about %% not working at the command prompt. However, ^ does not escape % there - a subtle distinction, but one that matters: ^% prints just %, because ^ placed before any char in an unquoted string is dropped on output - whether that char needs escaping or not. But, since ^ cannot escape %, the "specialness" of % is not deactivated by ^ - try echo ^%CD% - it's the same as echo %CD%. echo ^%CD^% works, but only due to cmd.exe now thinking that the variable name is CD^, and a undefined var. reference is left as-is.Unrefined
U
35

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.

Unrefined answered 15/7, 2015 at 2:2 Comment(4)
For me "%%" worked for a batch file in windows 7 sendto: command ffmpeg -i %1 ./image"%%"05d.png where in cmd the command would be ...image%05d.png.Acuff
@Phann: Re batch file: You don't need the "..." around %%, and I suggest not using it in general, as not all target programs may strip the token-internal " chars. for you. If a token needs double-quoting for the other characters contained in it, double-quote it as a whole.Unrefined
See my answer how to use literal percent signs on the command line, even inside quotesFic
Thank you this is such a comprehensive answer. I've been searching for a while and couldn't find my answer until now.Solecism
S
16

In batch files, the percent sign may be "escaped" by using a double percent sign ( %% ). That way, a single percent sign will be used within the command line. from http://www.robvanderwoude.com/escapechars.php

Staples answered 28/3, 2011 at 6:36 Comment(2)
And to understand, why a percent sign can only be escaped with a percent sign and not with a caret, you can read at how cmd.exe parse scriptsFic
If part of a command line though you still need a ^ if you are trying to escape a variable, placing the ^ inside the variable name will stop it expanding. Something like %Variable^Name% will escape as %VariableName% and not be expanded.Lasting
F
3

How to "escape" inside a batch file withoput modify the file** The original question is about a generated file, that can't be modified, but contains lines like:

move /y "\\myserver\myfolder\file%20name.txt" "\\myserver\otherfolder"

That can be partly solved by calling the script with proper arguments (%1, %2, ...)

@echo off

set "per=%%"
call generated_file.bat %%per%%1 %%per%%2 %%per%%3 %%per%%4

This simply sets the arguments to:

arg1="%1"
arg2="%2"
...

How to add a literal percent sign on the command line

mklement0 describes the problem, that escaping the percent sign on the command line is tricky, and inside quotes it seems to be impossible.

But as always it can be solved with a little trick.

for %Q in ("%") do echo "file%~Q20name.txt"

%Q contains "%" and %~Q expands to only %, independent of quotes.

Or to avoid the %~ use

for /F %Q in ("%") do echo "file%Q20name.txt"
Fic answered 29/10, 2020 at 7:52 Comment(0)
M
1

I think I've got a partial solution working. If you're only looking to transfer files that have the "%20" string in their name and not looking for a broader solution, you can make a second batch file call the first with %%2 as the second parameter. This way, when your program tries to fetch the second parameter when it hits the %2 in the text name, it will replace the %2 with an escaped %2, leaving the file name unchanged.

Hope this works!

Masticatory answered 29/6, 2015 at 16:19 Comment(1)
This is essentially the same as the accepted answer, where use of ^%2 as the 2nd parameter is proposed; the only difference is the syntax - ^%2 vs. %%2, which is explained by the difference between generating a literal % on the command line (the ^ actually has no effect here) vs. inside a batch file.Unrefined
V
-3

You should be able to use a caret (^) to escape a percent sign.

Editor's note: The link is dead now; either way: It is % itself that escapes %, but only in batch files, not at the command prompt; ^ never escapes %, but at the command prompt it can be used indirectly to prevent variable expansion, in unquoted strings only.

The reason %2 is disappearing is that the batch file is substituting the second argument passed in, and your seem to not have a second argument. One way to work around that would be to actually try foo.bat ^%1 ^%2... so that when a %2 is encountered in a command, it is actually substituted with a literal %2.

Verney answered 15/12, 2009 at 12:24 Comment(4)
You can't escape a percent sign with a caret, only with a percent signFic
@Unrefined Technically you can't escape a percent sign on the command line. The only cause why it seems to work is that cmd.exe searches for the variable username^ in %username^%, so you can also use %user^name% it has nothing to do with escaping a percent. Btw foo.bat ^%1 ^%2 is useless at all, as the carets are simply removed after the %1 and %2 are expanded. See also How variables are expandedFic
As @Fic points out, ^ cannot actually escape %, despite generally acting as the escape character in unquoted strings. However, you can use ^ to effectively suppress variable expansion by placing it before, after, or inside the variable name, but that only works on the command line, not inside batch files. The rest of the answer provides a clever solution to the OP's very specific problem: needing to deal with an ill-formed, auto-generated batch file; this specificity of the OP's problem is at odds with how generic the title of the question is, which invites confusion.Unrefined
@jeb: Again, thanks for the clarification re escaping %. The ^ in ^%2 is useless here, but does no harm: the proposed solution works with both ^%2 and %2, because - as far as I know - an interactive cmd.exe shell never has parameters, and so a reference such as %2 is retained as is (treated as a literal; by contrast, you'd have to use %%2 when calling from another batch file). Using %^2 to be safe and explicit is also an option.Unrefined

© 2022 - 2024 — McMap. All rights reserved.