如何将包含脱字符(^)的密码作为参数传递给Windows批处理文件时保持不变?

15

摘要:
我在Windows Server 2003 R2的命令行中输入以下命令:

> SET password=a^b  
> ECHO %password%
并且结果是 "ab"。这该死的插入符号(^)去哪了?我试图用 ^^、`^、%^、^^^ 进行“转义”,但是没有任何一种方式可以让插入符号传递到 echo 命令。这个批处理文件在中间,所以我既无法更改源系统的密码以避免使用插入符号,也无法更改目标系统的密码以使其与源系统不同步。

详情:
我在Google和 Stackoverflow 上进行了搜索。虽然现在我有了大量关于如何更好地设计我的Windows批处理文件的技巧,但我的问题仍然存在。

我有一个名为 run.bat 的批处理文件,其中包含一系列 SET 语句,用于设置运行Java命令行应用程序的上下文。在“cd”到正确的文件夹后,在Windows Server 2003 R2 上的命令行提示符中输入:

> run the_name the_pass^word
当我查看输出到命令行的内容时,我看到“java...config.user_name=the_name config.password=the_password”,其中“...”是一堆与此问题不相关的参数和库的噪音。该该死的插入符(^)消失了。
我尝试了各种转义策略,试图使插入符显示出来。除了将密码用引号括起来之外,我没有找到任何能够让插入符出现的方法,例如我键入:
> run the_name "the_pass^word"

...然后生成的命令行看起来像:

java...config.user_name=the_name config.password="the_pass^word"
即我得到了插入符号,但引号现在出现在字符串的内容中...这对于它们被传递到应用程序是自然无法工作的。
有没有人有任何明显的提示或技巧可以让我输入的参数在命令行上通过不受触摸地传递到我的内部利用?该值实际上已经到达批处理文件变量%2。但是,第一次查看%2的内容时,它已被“剥夺”。
呃,我不喜欢Windows批处理文件。
更新: 感谢Joshua McKinnon的回答。我选择他的答案,因为它解决了我的即时问题。但是,我想进一步阐述解决方案(是的,复数)。
  1. 不需要使用任何形式的SetLocal / EndLocal
  2. 必须使用%~1样式语法-找不到保留插入符的任何形式的%1语法
  3. 解决方案:未引用,使用4个连续的插入符(例如:使用pass^^^^word生成pass^word)
  4. 解决方案:引用,使用2个连续的插入符(例如:使用“pass^^word”生成pass^word)
在批处理文件“run.bat”中,使用%~1语法,如:
java MyClass username=%~1 password=%~2

...然后在命令行中输入:

> run mr_clean puke^^^^boy  
或者
> run mr_clean "puke^^boy"  

这将导致最终执行的语句如下所示:

java MyClass username=mr_clean password=puke^boy  

希望这能帮助其他人节省一些时间。我花了6个小时的时间试图追踪这个怪异问题(更像是白痴-同步性)。


如果你在你的“^^”前面再打两个“^^”,你本可以节省6个小时。 - Pacerier
这几乎有所帮助,但是我遇到了一个问题,即在调用时插入符号 ^ 会被加倍。这个SO答案https://dev59.com/02nWa4cB1Zd3GeqPwATG#12656803解释了这个问题,并展示了如何通过引用传递变量,这对我解决了问题。 - Mark Berry
5个回答

17

根据这个页面所说,在Windows批处理文件中,& | ( < > ^都是保留字符。^既是转义字符,也是换行符。使用^^应该可以得到一个^,但是那个^可能需要被转义。

如果想通过输入获取密码,你尝试过将插入符号的数量增加到四个吗?

e.g.:  my_batch.cmd the_pass^^^^word

1
哦,天啊!我尝试了3,但没有做4。使用%~1(引号剥离)语法有两个解决方案。A)如果不带引号提供,则4个脱字符一起工作。B)如果提供引号,则2个脱字符一起工作。我无法使用%1(原始非引号剥离)语法使插入符号始终响应。 - chaotic3quilibrium
3
之所以需要4是因为每次处理时,每个^^都会变成^。所以当参数被读取时,它从^^^^变成^^,当该变量被读取并放入另一个变量中时,它会从^^变成^。如果它被处理第三次,你就需要更多。(每次都是两倍,每次。)幸运的是,看起来它在那一点停止了 :) - Joshua McKinnon

3
主要问题在于,当行中出现插入符号和其他特殊字符时(不在引号内),它们总是会被处理。
当使用%var%扩展时,内容也会被解析,但不适用于!var!的延迟扩展。
示例:
@echo off
setlocal Enabledelayedexpansion

set variabl=-^^"^^-
set variabl
echo delayed !variabl!
echo percent %variabl%

--- Output ---
variabl=-^"^^-
delayed -^"^^-
percent -"^-

变量的内容是-^"^^-,这就是set行的问题所在。但是当与%var%一起使用时,插入符号只能作为转义字符。

你是批处理忍者吗? - Pacerier
@Pacerier 无论如何,我会努力成为一名程序员。 - jeb

3
这解释了问题:

http://www.robvanderwoude.com/battech_inputvalidation_commandline.php

如果您在批处理文件/CMD脚本中处理任意字符串,请不要通过命令行参数传递它们!相反,将它们放入文件中,并让批处理文件读取它们。因为命令行参数的验证和净化永远不能百分之百保证安全。

0
我有一个脚本将一个变量传递给另一个脚本。我不得不引用我的双引号:
问题(当通过Java进行加密时,密码中的“carrot”被删除):
 .\encrypt.bat -e "Some^Pass;W0rd" C:\Users\path\to\encryption.key
 //Decryption result: SomePass;W0rd

解决方案:
.\encrypt.bat -e '"Some^Pass;W0rd"' C:\Users\path\to\encryption.key
//Decryption Result: Some^Pass;W0rd

0

去掉引号可能会更容易。请参阅此SO链接以获取一些信息。


谢谢提供链接。去除引号的代码也会将插入符号一起删除。至少在尝试了多种变化后,这是结果。 - chaotic3quilibrium
原来这是剥离引号语法(参见您提供的链接)和两种转义转义字符技巧的组合(请参阅我的原始帖子中的更新)的结合。 - chaotic3quilibrium

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