perlipcopen3

perl IPC::Open3 adds additional quotes to command arguments that have quotes


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:

  1. my @cmd = ('ls', "--color='auto'");
  2. my @cmd = ('ls', '--color=\'auto\'');
  3. 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.


Solution

  • 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.