Ignore percent sign in batch file

后端 未结 6 2379
北恋
北恋 2020-11-22 14:33

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 \"

6条回答
  •  醉梦人生
    2020-11-22 15:08

    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: & | < > "

        • Alternatively, if the target program supports it (should with work with most binary executables, but not with batch files), you can represent % chars. as "%"; e.g.:

           echo "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.

提交回复
热议问题