Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl escaping argument for bash execution

I've written some code in Perl which executes some bash command within its execution. My problem was when bash command attributes contained white space inside which failed bash command execution. But I've managed to work with those argument simply adding quotes around argument. Unfortunately during tests I've found that my script fails when \ character is placed at the end of variable which obviously escapes bash execution quotes and fails bash command. For example:

my $arg1 = 'This is sample text which can be put into variable. And a random sign\\';
`echo "$arg1"`

Is there any chance to automatically escape special characters in variable?

like image 961
J33nn Avatar asked Jul 21 '14 15:07

J33nn


3 Answers

It's much easier to use single quotes in bash; then the only character you need to worry about is a single quote itself.

($arbitrary_string) =~ s/'/'"'"'/g;

`echo '$arbitrary_string'`
like image 167
ysth Avatar answered Oct 23 '22 22:10

ysth


CPAN to the rescue.

String::ShellQuote should do what you need, although I concur with @glennjackman that system (or Capture::Tiny) is a better approach:

use String::ShellQuote 'shell_quote';

my $cmd = shell_quote( 'echo', 'This is sample text ending in a slash \\' );

`$cmd`;
like image 4
Diab Jerius Avatar answered Oct 24 '22 00:10

Diab Jerius


Don't use backticks to keep your string away from the shell, and hence all the quoting issues:

system 'echo', $var;

You write:

I need stdout from this command unfortunately. Other thing is that variables are used in a lil bit complicated command which uses many pipes and stuff: echo $var | sed | grep | awk | and so on... and so on...

You might want to investigate with something like this (untested, largely cribbed from the IPC::Open3 perldoc)

use IPC::Open3;
use Symbol 'gensym';

my ($wtr, $rdr, $err);
$err = gensym;
my $pid = open3($wtr, $rdr, $err, 'sed|grep|awk|and so on');
print $wtr $var;
close $wtr;
my $output = <$rdr>;
waitpid $pid, 0;

If your pipeline is very messy, store it in a shell script file, and invoke that script from perl.

like image 2
glenn jackman Avatar answered Oct 23 '22 22:10

glenn jackman