什么时候引用的参数的双引号传递给被调用的批处理文件/程序?

时间:2015-11-30 07:35:02

标签: 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 = 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文件?

2 个答案:

答案 0 :(得分:1)

TL; DR:这取决于shell的实现。在Windows上,cmd控制台引用使用与bash shell不同的规则。 source

我相信你一直在寻找:

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

See the documentation.

Tilde角色有特殊的"修饰符"批处理参数的含义。如果你考虑一下,Perl和批处理是两种不同的语言,当一个程序被发送参数时,想想它就像它传递了一个查询字符串,除了它决定如何解析语言它。真正传递给程序的是一个长参数但是程序在空格上分开,同时牢记引号和转义。
您还可以看到@echo 0: %0会在引号中显示该程序,而@echo 0: %~0会删除双引号。

要查看"参数"的全部内容。传递给脚本,没有被解析,你做了:
@echo *: %*
正如您所看到的,脚本实际上是传递一个长参数并且必须首先解析,保留空格和引号,并记住^之类的转义字符,以便创建多个"论证的概念"。

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

修改
在玩了一段时间后,我开始认为这超出了Perl的控制范围。在从命令行测试print_r($argv);时,我也注意到与PHP相同的行为,它也会丢失其引号。

您可以通过运行:

看到Perl通过引号发送参数
use Win32::API;
my $GetCommandLine = Win32::API->new('kernel32', 
    'GetCommandLine', [ ] , 'P' );
$cmdline = $GetCommandLine->Call();
    print $cmdline;

但是,如果您只想要参数而不是完整的命令行命令,那么您需要解析它。

这里发布的问题与您的完全一样:
http://www.nntp.perl.org/group/perl.beginners/2002/07/msg29597.html
在第二页上解释彼得斯科特的回答:在程序看到参数之前,shell会执行空格分裂和解释,并且程序编写的语言没有区别。所以你必须要找到一个解决方法。

答案是非常一致的,它是一个shell问题,我研究的越多 例如,即使在Python中,它也是same issue

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

答案 1 :(得分:0)

考虑

call :somesubroutine %*

如果没有引号,somesubroutine会看到6个参数。看到3。

真的是定义问题,但批量似乎在这里说实话。

还要考虑

会发生什么
x:\show_parameters.bat "foo bar" "" "one two three"