Cmd 何时将带引号参数的双引号传递给被调用的批处理文件/程序?

Cmd 何时将带引号参数的双引号传递给被调用的批处理文件/程序?,cmd,arguments,Cmd,Arguments,下面是一个简单的.bat文件,其中显示了执行bat文件的前三个参数: @echo 1: %1 @echo 2: %2 @echo 3: %3 当我像这样执行bat文件时 c:\> x:\show_parameters.bat "foo bar" baz "one two three" 输出是 1: "foo bar" 2: baz 3: "one two three" 我很惊讶,因为我没想到双引号会作为参数的一部分被传递 当我使用Perl脚本显示参数值时 my $arg_cnt =

下面是一个简单的
.bat
文件,其中显示了执行bat文件的前三个参数:

@echo 1: %1
@echo 2: %2
@echo 3: %3
当我像这样执行bat文件时

c:\> x:\show_parameters.bat "foo bar" baz "one two three"
输出是

1: "foo bar"
2: baz
3: "one two three"
我很惊讶,因为我没想到双引号会作为参数的一部分被传递

当我使用Perl脚本显示参数值时

my $arg_cnt = 1;
for my $arg (@ARGV) {
  printf "%2d: %s\n", $arg_cnt, $arg;
  $arg_cnt++;
}
然后像这样执行脚本

c:\> x:\show_parameter.pl "foo bar" baz "one two three"
它打印

 1: foo bar
 2: baz
 3: one two three
也就是说,没有任何双引号。这是bat变体的预期行为


那么,为什么参数传递给bat文件的方式不同呢;DR:这取决于shell实现。在windows上,
cmd
控制台引用使用与bash shell不同的规则


我相信您正在寻找:

@echo 1: %~1
@echo 2: %~2
@echo 3: %~3

波浪线字符对于批处理参数具有特殊的“修饰符”含义。如果你想一想,Perl和batch是两种不同的语言,当一个程序被发送参数时,你可以把它看作是传递了一个查询字符串,除非它是由语言决定如何解析它。实际上,传递给程序的是一个长参数,但程序会在空格上拆分,同时记住引号和转义。
您还可以看到
@echo 0:%0
将以引号显示程序,而
@echo 0:%~0
将删除双引号

要查看传递给脚本的完整“参数”行,而不进行解析,您需要执行以下操作:
@echo*:%*

如您所见,脚本实际上传递了一个长参数,必须首先进行解析,记住空格和引号以及转义字符,如
^
,以便创建多个“参数”的概念

就Perl的行为而言,我猜想Perl在填充
ARGV
时会自动为您执行此操作。如果您对Perl使用的逻辑感兴趣,可以检查它

编辑
在使用它一段时间后,我开始认为这超出了Perl的控制范围。我在测试
print\r($argv)时也注意到了PHP的相同行为从命令行,它也会丢失其引号

您可以看到,通过运行以下命令,Perl将收到带引号的参数:

use Win32::API;
my $GetCommandLine = Win32::API->new('kernel32', 
    'GetCommandLine', [ ] , 'P' );
$cmdline = $GetCommandLine->Call();
    print $cmdline;
但是如果只需要参数,而不是完整的命令行命令,那么就需要解析它

这里有一个问题和你的问题一模一样:

解释一下Peter Scott在第二页上的回答:shell在程序看到参数之前进行空格拆分和去引号,并且它对程序使用的语言没有任何影响。所以你必须找到一个解决办法

答案是非常一致的,我越是研究它,它就是一个空壳问题。
例如,即使在Python中,它也是

那个么为什么批处理会给出不同的结果呢?这取决于shell实现。在windows上,cmd控制台引用使用与bash shell不同的规则

考虑

call :somesubroutine %*
如果没有引号,
somesubroutine
将看到6个参数。带着它的3

这确实是一个定义问题,但批处理似乎在这里说实话

还可以考虑一下,在这种情况下会发生什么

x:\show_parameters.bat "foo bar" "" "one two three"

Tilde解决了我处理引用参数的问题,因为它们从一个脚本传递到另一个脚本——谢谢!