2

Here's a simple .bat file that shows the first three arguments with which the bat file is executed:

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

When I execute the bat file like so

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

the output is

1: "foo bar"
2: baz
3: "one two three"

I was surprised, because I didn't expect the double quotes to be passed as part of the arguments.

When I use a Perl script to show the values of the parameters

my $arg_cnt = 1;
for my $arg (@ARGV) {
  printf "%2d: %s\n", $arg_cnt, $arg;
  $arg_cnt++;
}

and execute the script like so

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

it prints

 1: foo bar
 2: baz
 3: one two three

that is, without any double quotes. This is the, imho, expected behaviour for the bat variant.

So, Why are the arguments passed differently to the bat file?

René Nyffenegger
  • 39,402
  • 33
  • 158
  • 293

2 Answers2

1

TL;DR: It depends on the shell implementation. On windows, the cmd console quoting uses different rules from the bash shell. source


I believe you're looking for:

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

See the documentation.

The Tilde character has special "modifier" meaning with batch parameters. If you think about it, Perl and batch are two different languages, and when a program is sent parameters, think of it like it's passed a query string, except it's upto the language to decide how to parse it. Really what you pass to the program is one-long parameter but the program splits on spaces while keeping in mind quotes and escaping.
You can also see @echo 0: %0 will show you the program in quotes while @echo 0: %~0 removes the double quotes.

To see the full line of "arguments" passed to the script, without being parsed, you'd do:
@echo *: %*
As you can see, the script is really passed one long argument and has to be parsed first, keeping spaces and quotes, and escape characters such as ^ in mind, in order to create the concept of multiple "arguments".

In terms of Perl's behavior, my guess is that Perl does this automagically for you when populating ARGV. Could check its source code if you're interested in the logic Perl is using.

Edit:
After playing with it for a while, I'm starting to think this is beyond Perl's control. I'm noticing the same behavior with PHP as well when testing print_r($argv); from commandline and it also loses its quotes.

You can see Perl is getting sent the parameters with quotes by running:

use Win32::API;
my $GetCommandLine = Win32::API->new('kernel32', 
    'GetCommandLine', [ ] , 'P' );
$cmdline = $GetCommandLine->Call();
    print $cmdline;

But then you'd need to parse that if you wanted just the parameters and not the full command line command.

There's a question posted here exactly like yours:
http://www.nntp.perl.org/group/perl.beginners/2002/07/msg29597.html
To paraphrasing Peter Scott's answer there on the 2nd page: the shell does the whitespace splitting and dequoting before the program sees the arguments and it makes no difference what language the program is written in. So you'll have to find a workaround.

The answer is pretty consistent that it's a shell issue the more I research it.
For example even in Python, it's the same issue.

So why does batch give different results? It depends on the shell implementation. On windows, the cmd console quoting uses different rules from the bash shell.

Community
  • 1
  • 1
Ultimater
  • 4,647
  • 2
  • 29
  • 43
0

consider

call :somesubroutine %*

Without the quotes, somesubroutine would see 6 arguments. With its sees 3.

Really a matter of definition, but batch seems to tell the truth here.

Consider also what happens with

x:\show_parameters.bat "foo bar" "" "one two three"
Magoo
  • 77,302
  • 8
  • 62
  • 84