Escaping parentheses in perl backticks for bash command

Viewed 231

I have been using backticks for years but this is the first time I have tried using a command with a parentheses. I am getting an error that I cannot figure out.

I have tried putting in double quotes and escaping with the \ in multiple places, but nothing seems to work. Any help would be appreciated.

COMMAND the $file5 and $file6 are perl variables, not bash.

@array = `/usr/bin/join -j 1 -t, <(cat $file5 | awk -F, '{print \$3","\$1}' | sort) <( cat $file6 | awk -F, '{print \$3","\$1}' | sort) `

ERROR: AH01215: sh: -c: line 0: syntax error near unexpected token `(', referer:

2 Answers

Backticks use /bin/sh, and while <( ... ) is something recognized by bash, it's not recognized by the bourne shell. If you use backticks, you will need to use

my $bash_cmd = ...;
my @lines = `bash -c $bash_cmd`;

Building sh and bash shell commands can be done using String::ShellQuote.

use String::ShellQuote qw( shell_quote );

my $file5_quoted = shell_quote($file5);
my $file6_quoted = shell_quote($file6);

my $awk_cmd = shell_quote("awk", "-F,", '{print $3","$1}');

my $bash_cmd = '/usr/bin/join -j 1 -t,'
   . " <( $awk_cmd $file5_quoted | sort )"
   . " <( $awk_cmd $file6_quoted | sort )";

my $sh_cmd = shell_quote("bash", "-c", $bash_cmd);
my @lines = `$sh_cmd`;

We can use IPC::System::Simple's capturex to avoid launching more shells than needed, as well as to provide error checking. To do this, replace the last two lines of the above with the following:

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

my @lines = capturex("bash", "-c", $bash_cmd);

One workaround is to create a shell script that accepts the two filenames from perl, processes the join using those two input files, and return the result to the perl array.

#1. Create join.sh that contains these four lines:

    cat $1 | awk -F, '{print $3","$1}' | sort > 1.out
    cat $2 | awk -F, '{print $3","$1}' | sort > 2.out
    /usr/bin/join -j 1 -t, 1.out 2.out
    rm 1.out 2.out


#2. Modify your perl statement to call join.sh as follows:

    @array=`join.sh $file5 $file6`;
Related