tomsk
tomsk

Reputation: 997

Escape special characters in JSON string

I have Perl script which contains variable $env->{'arguments'}, this variable should contain a JSON object and I want to pass that JSON object as argument to my other external script and run it using backticks.

Value of $env->{'arguments'} before escaping:

$VAR1 = '{"text":"This is from module and backslash \\ should work too"}';

Value of $env->{'arguments'} after escaping:

$VAR1 = '"{\\"text\\":\\"This is from module and backslash \\ should work too\\"}"';

Code:

print Dumper($env->{'arguments'});
escapeCharacters(\$env->{'arguments'});
print Dumper($env->{'arguments'});

my $command = './script.pl '.$env->{'arguments'}.'';
my $output = `$command`;

Escape characters function:

sub escapeCharacters
{
    #$env->{'arguments'} =~ s/\\/\\\\"/g;
    $env->{'arguments'} =~ s/"/\\"/g;
    $env->{'arguments'} = '"'.$env->{'arguments'}.'"';
}

I would like to ask you what is correct way and how to parse that JSON string into valid JSON string which I can use as argument for my script.

Upvotes: 1

Views: 2573

Answers (2)

ikegami
ikegami

Reputation: 385986

You're reinventing a wheel.

use String::ShellQuote qw( shell_quote );

my $cmd = shell_quote('./script.pl', $env->{arguments});
my $output = `$cmd`;

Alternatively, there's a number of IPC:: modules you could use instead of qx. For example,

use IPC::System::Simple qw( capturex );

my $output = capturex('./script.pl', $env->{arguments});

Because you have at least one argument, you could also use the following:

my $output = '';
open(my $pipe, '-|', './script.pl', $env->{arguments});
while (<$pipe>) {
   $output .= $_;
}

close($pipe);

Note that current directory isn't necessarily the directory that contains the script that executing. If you want to executing script.pl that's in the same directory as the currently executing script, you want the following changes:

Add

use FindBin qw( $RealBin );

and replace

'./script.pl'

with

"$RealBin/script.pl"

Upvotes: 2

clockwatcher
clockwatcher

Reputation: 3363

Piping it to your second program rather than passing it as an argument seems like it would make more sense (and be a lot safer).

test1.pl

#!/usr/bin/perl

use strict;
use JSON;
use Data::Dumper;

undef $/;

my $data = decode_json(<>);
print Dumper($data);

test2.pl

#!/usr/bin/perl

use strict;
use IPC::Open2;
use JSON;

my %data = ('text' => "this has a \\backslash", 'nums' => [0,1,2]);
my $json = JSON->new->encode(\%data);

my ($chld_out, $chld_in);
print("Executing script\n");
my $pid = open2($chld_out, $chld_in, "./test1.pl");
print $chld_in "$json\n";
close($chld_in);
my $out = do {local $/; <$chld_out>};
waitpid $pid, 0;
print(qq~test1.pl output =($out)~);

Upvotes: 1

Related Questions