Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Oh Wise Monks,

A need recently arose to pipe an arbitrary (short) string into a shell command and get the results. I wanted to avoid open2, and thought: the biggest issue is that some malicious person might try to inject things like "$" and quote characters, etc. No problem: I can write something that converts my input string into something that the Unix command printf (or echo -e) will interpret into the correct string, which then gets piped to the command. But then it didn't work:

$cmd = "printf 'I\\x27ll'"; print $cmd . "\n"; print `$cmd` ."\n";

printf 'I\x27ll'
I\x27ll

I am confused because the shell gives the result I want, but backticks (and open '-|') do not!

> printf 'I\x27ll'
I'll
Help??

Replies are listed 'Best First'.
Re: backslashes in shell commands
by kcott (Archbishop) on Mar 09, 2013 at 04:04 UTC

    You escaped the backslash: that worked fine. What you didn't do was escape the single quotes.

    #!/usr/bin/env perl use strict; use warnings; my $cmd = "printf \'I\\x27ll\'"; print $cmd . "\n"; print `$cmd` ."\n";

    Output:

    $ pm_sh_escape.pl printf 'I\x27ll' I'll

    Update: Escaping the single quotes was not the answer - see discussion below.

    -- Ken

      Ken, running you code, I get:
      ./backslash.pl
      printf 'I\x27ll'
      I\x27ll

      If it helps -- my perl version is v5.14.2 on x86_64-linux-gnu-thread-multi.

        I have the same Perl version as you but a different O/S:

        $ perl -v This is perl 5, version 14, subversion 2 (v5.14.2) built for darwin-th +read-multi-2level ... $ uname -a Darwin ganymede 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:25: +48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64

        It would appear that I gave you something of a bum steer regarding escaping the single quotes - sorry about that. Removing the two backslashes before the single quotes does not alter the outcome for me:

        $ cat pm_sh_escape.pl #!/usr/bin/env perl use strict; use warnings; my $cmd = "printf 'I\\x27ll'"; print $cmd . "\n"; print `$cmd` ."\n";
        $ pm_sh_escape.pl printf 'I\x27ll' I'll

        Checking directly in the shell, I get the same result as you:

        $ printf 'I\x27ll' I'll

        Unfortunately, that all adds up to an inability to reproduce your problem.

        -- Ken

Re: backslashes in shell commands
by Khen1950fx (Canon) on Mar 09, 2013 at 15:02 UTC
    A good substitute for backticks is the capturex function from IPC::System::Simple. It's like backticks in list context, and it will not invoke the shell. If you want the shell, then use the capture function. For example:
    #!/usr/bin/perl -l use strict; use warnings; use IPC::System::Simple qw/capturex/; my @args = "%s I\x27ll"; my $cmd = capturex("printf", @args); print $cmd;
    I really hope this helps you.
Re: backslashes in shell commands
by Anonymous Monk on Mar 09, 2013 at 05:30 UTC