在批处理文件中忽略百分号

40

我有一个批处理文件,可以将文件从一个文件夹移动到另一个文件夹。这个批处理文件是由另一个过程生成的。

我需要移动的一些文件名中包含字符串"%20":

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

这个失败是因为它试图查找一个名字为:

\\myserver\myfolder\file0name.txt

有没有办法忽略%?我无法更改生成的文件以进行转义,例如通过加倍百分号 (%%),使用/^(脱字符)进行转义等。


3
你应该接受rud3y的答案。 - Griffin
1
正如我所说,我无法更改生成的文件。我得到的文件名带有百分号:file%20name.txt。我无法在其中添加额外的百分号。 - Stagg
1
可能是在bat文件中转义百分号的重复问题。 - phuclv
6个回答

63

在这种情况下,您需要使用%%。通常使用^(插入符号)会起作用,但对于%符号,您需要将其加倍。

对于%%1%%iecho.%%~dp1,因为%表示输入来自命令或变量(当用%包围时; %variable%

要实现您的需求:

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

希望这能帮到你!


请注意,%% 仅在批处理文件中起作用,而在命令提示符本身中则不起作用。在命令提示符本身中,插入一个折行符可使百分号转义为 ^% 并显示 % - Michael Plautz
@MichaelPlautz:关于命令提示符下%%无法使用的观点很好。 但是,在该处,^并不转义% - 这是一种微妙的区别,但很重要: ^%只打印,因为在未引用字符串中的任何字符之前放置的^在输出时都会被删除 - 无论该字符是否需要转义。 但是,由于^无法转义,因此的“特殊性”未被^去激活 - 尝试echo ^%CD% - 它与echo %CD%相同。 echo ^%CD ^%有效,但仅由于cmd.exe现在认为_变量名称_是CD ^,而_未定义_的变量引用保持原样。 - mklement0

35

这个问题的标题非常泛化,这不可避免地吸引了很多寻找通用解决方案的读者。
相比之下,问题提出者的问题是非常奇特的:需要处理一个格式不正确且无法修改的自动生成的批处理文件:%符号在其中没有被正确转义。
被接受的回答 提供了一个巧妙的解决方案,针对这个具体-而奇特-问题,但会在处理通用问题时造成混乱。

如果我们关注通用问题

如何将%作为批处理文件/命令行中的字面值字符?

  • 批处理文件中,始终将%视为%%进行转义,无论是在未加引号的字符串中还是在加引号的字符串中;例如下面的语句将产生My %USERNAME% is jdoe

      echo My %%USERNAME%% is %USERNAME%
      echo "My %%USERNAME%% is %USERNAME%"
    
  • 在命令行(交互式)- 以及在使用脚本语言的shell-invoking函数时 -行为基本上与批处理文件内部的行为不同:从技术上讲,在这里%无法被转义,并且没有一个适用于所有情况的单一解决方法

    • 未加引号的字符串中,您可以使用"^名称破坏器"技巧:为了简单起见,在每个%字符之前加上^,但请注意,这样做并不是技术上的转义%的方法(有关更多信息,请参见下文);例如,以下内容再次产生类似于My %USERNAME% is jdoe的结果:

       echo My ^%USERNAME^% is %USERNAME%
      
    • 在双引号字符串中,您根本无法转义 %,但有一些解决方法

      • 您可以像上面那样使用未引用字符串,这需要您额外对所有其他shell元字符进行^转义,这很麻烦; 这些元字符是:<space> & | < > "

      • 或者,除非您正在调用批处理文件,您可以将单独的双引号括起来%字符串作为复合参数的一部分(大多数外部程序和脚本引擎将解析诸如"%"USERNAME"%"的复合参数作为逐字字符串%USERNAME%):

         some_exe My "%"USERNAME"%" is %USERNAME%
        
    • 如果您知道自己在调用二进制可执行文件,则可以通过放弃使用调用shell的函数而选择“无壳”变量来避免整个问题,例如在Node.js中使用execFileSync代替execSync


关于命令行(交互式)使用的可选背景信息:

感谢jeb帮助完成此部分。

在命令行上(交互式),%技术上是不能被转义的; 而^通常是cmd.exe的转义字符,但它不适用于%

正如所述,对于双引号字符串没有解决方案,但对于未加引号的字符串有解决方法:

"^名称破坏者"技巧(类似于^%USERNAME^%)起作用的原因是:

  • 它“破坏”了变量名;也就是说,在上面的示例中,cmd.exe查找一个名为USERNAME^的变量,这个变量(希望)不存在。

  • 在命令行上 - 与批处理文件不同 - 对于未定义的变量的引用会保留为原样。

从技术上讲,在变量名中单个 ^ - 在其中的任何位置,只要它不紧挨着另一个^ - 就足够了,因此例如%USERNAME^%已经足够了,但我建议采用^在每个%之前严格遵循约定实现简单性,因为它也适用于像up 20^%这样的情况,其破坏甚至都不必要,但是是无害的,所以您可以有条不紊地应用它,而无需考虑输入字符串的细节。

未加引号的字符串中,在开头的%前放置一个^虽然不是必需的,但是是无害的,因为^转义下一个字符,无论该字符是否需要转义-或者在这种情况下是否可以转义。 其结果是这些^实例最终会从未加引号的字符串中删除

在很大程度上是假设性的警告: ^实际上是变量名称中的合法字符 (请参阅jeb在注释中的示例); 如果您的变量名以^结尾,请将“破坏性”^放置在变量名称的其他位置,只要它不直接紧挨着另一个^


1
对我来说,在Windows 7的sendto命令中,"%%"适用于批处理文件,命令为ffmpeg -i %1 ./image"%%"05d.png,而在cmd中,命令为image%05d.png - Phann
1
@Phann: 关于批处理文件:你不需要在%%周围加上"...",并且我建议总体上不要使用它,因为并非所有目标程序都会自动去除标记内部的"字符。如果一个标记需要以双引号括起来以包含其他字符,请整体双引号括起来。 - mklement0
1
请查看我的答案,了解如何在命令行上使用文字百分号,即使在引号内也可以。 - jeb
1
谢谢,这是非常全面的答案。我已经搜索了一段时间,直到现在才找到我的答案。 - Pouria P

16

5
要理解为什么百分号只能用另一个百分号转义而不能用插入符号转义,请参考如何解析cmd.exe脚本 - jeb
1
如果在命令行的一部分,但是如果你想要转义一个变量,仍然需要使用^,把^放在变量名内部可以防止变量被扩展。例如 %Variable^Name% 会被转义成 %VariableName% 而不会被扩展。 - user692942

3
如何在不修改文件的情况下,在批处理文件中进行“转义” 原始问题涉及一个生成的文件,不能被修改,但包含以下行:
move /y "\\myserver\myfolder\file%20name.txt" "\\myserver\otherfolder"

可以通过使用正确的参数(%1%2等)调用脚本来部分解决这个问题。

@echo off

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

这只是将参数设置为:
arg1="%1"
arg2="%2"
...

如何在命令行上添加一个百分号 mklement0描述了这个问题,在命令行上转义百分号很棘手,在引号内似乎不可能。
但是像往常一样,它可以通过一点小技巧解决。
for %Q in ("%") do echo "file%~Q20name.txt"

%Q 包含 "%"%~Q 会扩展为只有 "%",与引号无关。

或者可以避免使用 %~

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

1
我认为我已经有了一个部分解决方案。如果你只想传输文件名中包含"%20"字符串的文件,而不是寻找更广泛的解决方案,你可以创建一个第二个批处理文件,并将%%2作为第二个参数调用第一个批处理文件。这样,当程序尝试提取文本名称中的第二个参数时,它将用转义的%2替换%2,使文件名保持不变。
希望这能起作用!

1
这基本上与被接受的答案相同,其中建议使用^%2作为第二个参数; 唯一的区别是语法- ^%2 vs. %%2,这可以通过在命令行上生成文字%(此处实际上^没有任何效果)与在批处理文件内部进行解释来解释。 - mklement0

-3

你应该能够使用插入符号(^)来转义百分号

编辑注:链接已失效;无论如何:在批处理文件中,%本身可以转义%,但在命令提示符下不行;^从不转义%,但在命令提示符下,它可以在未加引号的字符串中被间接地用于防止变量扩展。

%2消失的原因是批处理文件替换了传递的第二个参数,而你似乎没有第二个参数。解决这个问题的一种方法是实际尝试foo.bat ^%1 ^%2...,这样当命令中遇到%2时,它实际上会被替换为文字%2


25
只有使用百分号才能转义百分号,插入符号无法实现该功能。 - jeb
3
从技术上讲,你不能在命令行中转义百分号。唯一的原因是cmd.exe在%username^%中搜索变量username^,所以你也可以使用%user^name%,这与转义百分号无关。另外,foo.bat ^%1 ^%2完全没有用处,因为carets在扩展%1%2后就被移除了。详情请参见变量的扩展方式 - jeb
1
正如@jeb所指出的那样,尽管在未引用字符串中通常作为转义字符,但^实际上不能转义%。 然而,您可以通过将其放置在变量名称之前、之后或之间来有效地抑制变量扩展,但这仅适用于命令行,而不适用于批处理文件。 答案的其余部分提供了一个聪明的解决方案,以解决OP的非常具体的问题:需要处理一个格式不正确的自动生成的批处理文件;这个问题的特殊性与问题的标题有所不同,这容易引起混淆。 - mklement0
1
@jeb:再次感谢您对于转义“%”的澄清。在“^%2”中,“^”是无用的,但不会造成任何影响:所提出的解决方案可以同时使用“^%2”和“%2”,因为据我所知,交互式的“cmd.exe” shell从来没有参数,因此像“%2”这样的引用保持原样(被视为文字;相比之下,在从另一个批处理文件调用时,必须使用“%%2”)。使用“%^2”以确保安全和明确也是一种选择。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接