I'm trying to use IPC::Open::open3()
(well, really IPC::Run::run()
but that calls open3()
)...and it has an odd behavior where if I pass a command line option with quotes, open3()
will add additional quotes around that option (sometimes escaped).
For example: I'm trying to run ls --color="auto"
and my output is:
ls: unsupported --color value '"auto"' (must be always, auto, or never)
Here's the code:
package test;
use strict;
use warnings FATAL => 'all';
use IPC::Open3;
use POSIX;
use Symbol qw/ gensym /;
my @cmd = ('ls', '--color="auto"');
my $child_stdout;
my $child_stderr = gensym;
my $child_pid = IPC::Open3::open3(undef, $child_stdout, $child_stderr, @cmd);
my @out = <$child_stdout>;
my @err = <$child_stderr>;
close($child_stdout);
close($child_stderr);
waitpid($child_pid, POSIX::WNOHANG);
print join("", @out);
print join("", @err);
1;
NOTE: I realize I can run ls --color=auto
...but there's another command I'm running that accepts strings with spaces in them which require quotes, ls is just a reproducible example.
I tried figuring out where in the source that IPC::Open3 is adding the quotes but I'm failing to where it's happening.
Long story short:
Thanks!
I've tried basic permutations like:
my @cmd = ('ls', "--color='auto'");
my @cmd = ('ls', '--color=\'auto\'');
my @cmd = ('ls', "--color=\"auto\"");
I've tried using IPC::Run::run()
like so: $success = IPC::Run::run(@cmd, \$in, \$out, \$err, IPC::Run::timeout(5));
However, I can't figure out a way to prevent IPC::Open3
from double quoting.
It turns out this had nothing to do with IPC::Open3 but it’s a behavior quirk of Perl where it escapes quoted parts of strings so it can print them later. I ended up using Data::Dumper::Dumper() right after setting @cmd and it was already quoted. So, I had to strip all quotes and do “—param=two words” when passing the param. I didn’t think that would work but since it’s ending up as it’s own param passed to execve/posix_spawn/whatever, there’s no need to quote the param value with spaces in it.
Sorry for getting people off track with the “—-color=‘auto’” example.
Another possibility was to try String::Escape::unprintable() but it was easier for me to just strip the quotes.