Getting 'system' to Process Win32 Paths Correctly

J

Jim Keenan

I wish to supply a user with a Perl distribution which includes a
command-line utility and whose test suite tests the output of that
utility. The test suite's call to that utility looks like this:

ok(! system("$^X -I$cwd/blib/lib $cwd/blib/script/utility"),
"able to call command-line utility");

where $^X is the name used to execute the current copy of Perl and $cwd
holds the name of the directory from which the test suite is called,
i.e., the directory holding Makefile.PL.

This works fine on my Unix-style system and fine on Win32 *provided*
that $cwd contains no wordspaces. So if the value of $cwd is
"C:/temp/other", the 'system' call correctly expands $cwd and the test
runs as intended.

However, if the value of $cwd is "C:/Documents and
Settings/localuser/My Documents", then the only part of the path that
get substituted is "C:/Documents". The "and" in "Documents and
Settings" is treated by perl as the program to be run, which causes an
error.

I've looked at the documentation for modules such as Cwd and File::Spec
and I don't see a workaround. So, ...

Can anyone suggest how to get 'system' to correctly interpret a
variable which holds a Win32 path which may contain wordspaces?

Thank you very much.
Jim Keenan
 
P

Paul Lalli

Jim said:
I wish to supply a user with a Perl distribution which includes a
command-line utility and whose test suite tests the output of that
utility. The test suite's call to that utility looks like this:

ok(! system("$^X -I$cwd/blib/lib $cwd/blib/script/utility"),
"able to call command-line utility");

where $^X is the name used to execute the current copy of Perl and $cwd
holds the name of the directory from which the test suite is called,
i.e., the directory holding Makefile.PL.

This works fine on my Unix-style system and fine on Win32 *provided*
that $cwd contains no wordspaces. So if the value of $cwd is
"C:/temp/other", the 'system' call correctly expands $cwd and the test
runs as intended.

I don't think this has anything to do with system(), so much as it has
to do with standard command line processing. If there are spaces in a
command line, they're taking to be argument-separators. If you want
them to mean actual spaces, you have to escape them - either by
prepending them with a backslash, or by enclosing the entire argument
in quotes:

ok(! system(qq|^X -I"$cwd/blib/lib" "$cwd/blib/script/utility"|),
"able to call command-line utility"

Paul Lalli
 
A

A. Sinan Unur

I wish to supply a user with a Perl distribution which includes a
command-line utility and whose test suite tests the output of that
utility. The test suite's call to that utility looks like this:

ok(! system("$^X -I$cwd/blib/lib $cwd/blib/script/utility"),
"able to call command-line utility");

....

However, if the value of $cwd is "C:/Documents and
Settings/localuser/My Documents", then the only part of the path that
get substituted is "C:/Documents".

The easy way is to wrap the file name in quotation marks:

system("$^X -Iqq{$cwd/blib/lib} qq{$cwd/blib/script/utility}");

On the other hand, for better portability, I would construct the
individual paths using File::Spec::catfile anyway.

By the way, there is a difference between calling system as above versus

system($^X, -I$cwd/blib/lib, $cwd/blib/script/utility);

D:\Home\asu1\UseNet\clpmisc> cat ttt.pl
#!/usr/bin/perl

use strict;
use warnings;

my $appdata = $ENV{APPDATA};

system "perl t2.pl $appdata";
system 'perl', 't2.pl', $appdata;
__END__

D:\Home\asu1\UseNet\clpmisc> cat t2.pl
#!/usr/bin/perl

use strict;
use warnings;

print "$_\n" for @ARGV;

__END__

D:\Home\asu1\UseNet\clpmisc> ttt
C:\Documents
and
Settings\asu1\Application
Data
C:\Documents and Settings\asu1\Application Data

Read

perldoc -f system

Sinan
 
A

A. Sinan Unur

I don't think this has anything to do with system(),

Indeed it does. There is a difference between passing a single scalar
string versus a list to system.

Sinan
 
P

Paul Lalli

A. Sinan Unur said:
Indeed it does. There is a difference between passing a single scalar
string versus a list to system.

Hrm. Good point. Trying to see if I understand perldoc -f system
correctly... so if a single string is passed, system lets the shell
parse the string into program + arguments, but if a list of more than
item is passed, system executes the first element, specifying the
remainder as arguments?

Good to keep in mind. Thanks for the reminder.

Paul Lalli
 
A

A. Sinan Unur

The easy way is to wrap the file name in quotation marks:

system("$^X -Iqq{$cwd/blib/lib} qq{$cwd/blib/script/utility}");

And, this, of course, is wrong. The correct version would have been:

system(qq{$^X -I"$cwd/blib/lib" "$cwd/blib/script/utility"});

My other comments regarding passing a list to system, and using
File::Spec::catfile to construct paths still apply, though.

Sinan
 
J

Jim Keenan

A. Sinan Unur said:
The correct version would have been:

system(qq{$^X -I"$cwd/blib/lib" "$cwd/blib/script/utility"});

Thanks, Sinan, this DWIMmed. A note for further reference: To pare
the original question down to its essence, I omitted options that the
command-line utility would normally call. When I tested the real code,
I had to add them back in. The quoting that worked for them went like
this:

ok(! system(qq{$^X -I"$cwd/blib/lib" "$cwd/blib/script/utility" -Icn
XYZ::ABC}),
"able to call utility");

Note that the option flags and arguments are not placed within the
quotation marks, but are still within the scope of the 'qq{}'.

Jim Keenan
 
B

Brian McCauley

A. Sinan Unur said:
Indeed it does. There is a difference between passing a single scalar
string versus a list to system.

Except this is Win32 - where there isn't a difference.

system(LIST) effectively joins the list with spaces and the CLI splits
it again (in all the wrong places).
 
A

A. Sinan Unur

Except this is Win32 - where there isn't a difference.

system(LIST) effectively joins the list with spaces and the CLI splits
it again (in all the wrong places).

I am not sure if you noticed my earlier example. Here is another one of
system(SCALAR) versus system(LIST). There clearly is a difference.

D:\Home\asu1\UseNet\clpmisc> cat hello.c
#include <stdio.h>

int main(int argc, char *argv[]) {
int i;
for(i = 0; i < argc; ++i) {
printf("%s\n", argv);
}
}

D:\Home\asu1\UseNet\clpmisc> cl hello.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for
80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

hello.c
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.

/out:hello.exe
hello.obj

D:\Home\asu1\UseNet\clpmisc> cat ttt.pl
#!/usr/bin/perl

use strict;
use warnings;

system "hello A. Sinan Unur ---";
system 'hello', 'A. Sinan Unur', '---';

D:\Home\asu1\UseNet\clpmisc> ttt.pl
hello
A.
Sinan
Unur
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top