Rainer Weikusat said:
Peng Yu said:
Suppose that I have a bash command in a string, e.g.
cmd.sh a 'a b' '
'
I want get an array consisting of "cmd.sh" "a" "a b" "\n". Is there
a robust way to do so in perl that can handle all the possible
cases?
[...]
sub shell_cmd_to_list
{
my ($all, @l, $one, $pos);
$all = `perl -e 'my \$v; \$v .= pack("Z*", \$_) for \@ARGV; print \$v' $_[0]`;
$pos = 0;
do {
$one = unpack('@'.$pos.'Z*', $all);
push(@l, $one);
$pos += length($one) + 1;
} while ($pos < length($all));
return @l;
}
Coming to think of this, this should probably rather be
----------------
sub shell_cmd_to_list
{
my ($all, @l, $one, $pos);
$all = `perl -e 'my \$v; \$v .= pack("Z*", \$_) for \@ARGV; print \$v' $_[0]`;
$? and return ();
$pos = 0;
while ($pos < length($all)) {
$one = unpack('@'.$pos.'Z*', $all);
push(@l, $one);
$pos += length($one) + 1;
}
return @l;
}
-----------------
which will return an empty list in case the shell encountered a synax
error in the argument string (alternatively, an exception could be
thrown) or if there were no arguments.
It should also be noted that this will not only perform command
substitution aka 'run arbitrary commands contained in the argument
string' but will also run an arbitrary 'trailing shell script'
attached to $_[0], IOW, it is completely unsuitable for processing
input from untrusted sources. OTOH, the shell already knows how to
parse 'shell commands' and using it to do this instead of
reprogramming the parser in Perl is IMHO generally sensible.
Special note: This is one of the rare cases where initializing a
variable is actually necessary in Perl because '@Z*' is not the same
as '@0Z*'.