'shell errors running php exec

I have a PHP script that executes a shell command to find the common items between two files given. This is the beginning of my PHP script:

$E7Bonded_File = "/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv";
$E7Single_File = "/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv";
$E7Common_File = "/opt/IBM/custom/NAC_Dslam/junk/Common_tn_SingleBonded_E7_cust_stats.csv";
//only do this once, with old single/bonded filenames. This will be a list to add to the existing Common file.
exec ("comm -12 <(cut -d ',' -f2 $E7Single_File| sort) <(cut -d ',' -f2 $E7Bonded_File| sort)", $outputCommon); 

I see this error message when I run the script:

sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `comm -12 <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv| sort)'

I checked, and the parentheses look ok for my exec() line.

When I run the shell command at the command line it returns a listing of numbers like I expect:

 comm -12 <(cut -d ',' -f2 junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 junk/PortParameter_E7_Bonded_cust_stats.csv| sort)

I looked online and I seem to be using exec() correctly. I want the numbers returned to be stored as an array, $outputCommon.

Any ideas about this error message?

*********Update on answer***************

My solution wound up being a combination of both mario and miken32/my co-worker

  1. Adding #!/bin/bash at the top of my php script, and
  2. Adding /bin/bash -c as follows:

    exec("/bin/bash -c /opt/IBM/custom/NAC_Dslam/Common_list.sh", $outputShell);

  3. After I moved the comm part to a shell script:

Common_list.sh:

#!/bin/bash
 comm -12 <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv| sort)


Solution 1:[1]

This error typically comes up for non-bash shells, which don't support <() expression pipes.

  • On Ubuntu/Debian servers the default /bin/sh is typically dash.

  • Check for symlinked binaries:

    me@snip:~$ ls -l /bin/sh
    lrwxrwxrwx 1 root root 4 Jul 16  2017 /bin/sh -> dash
    
  • Or as @theotherguy mentioned, bash runs as restricted_shell when started as sh.

  • See $_ENV[SHELL] on what Apache/PHP use as default. Change environment vars.

  • Either adapt that, or wrap the shell_exec cmdline with /bin/bash -c '…'.

Solution 2:[2]

Probably the easiest solution would be to make this into an executable script on the server:

#!/bin/bash
if [[ ! -r "$1" ]] || [[ ! -r "$2" ]]; then
    printf "File not found\n" >&2
    exit 1
fi

comm -12 <(cut -d ',' -f2 "$1"| sort) <(cut -d ',' -f2 "$2"| sort)

And then call that from PHP:

$E7Bonded_File = escapeshellarg("/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv");
$E7Single_File = escapeshellarg("/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv");

//only do this once, with old single/bonded filenames. This will be a list to add to the existing Common file.
exec ("/usr/local/bin/your_script.sh $E7Single_File $E7Bonded_File", $outputCommon); 

Always escape your shell arguments with escapeshellarg() even if you think they're safe.

Solution 3:[3]

when checking the script with a linter, it complains that:

comm -12 <(cut -d ',' -f2 junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 junk/PortParameter_E7_Bonded_cust_stats.csv| sort)
     ^-- SC2039: In POSIX sh, process substitution is undefined.

this happens when I define shebang #!/bin/sh, while #!/bin/bash does not complain... therefore the answer might be, to run the script with /usr/bin/bash. escapeshellarg() is indeed useful.

...

try shell_exec(), simply because exec() should not invoke any shell. the one returns the output as string and the other can return an array. alternatively, you can explicitly invoke bash with exec():

exec('/bin/bash -c "  command  "', $stdOut);

Solution 4:[4]

So in case anyone else still needs to get substitution working in command execution in PHP, there is super dumb simple thing to do:

$a = 'Hello substitution';
var_dump(shell_exec("bash -c 'cat <(echo $a)'"));

Results in:

string(19) "Hello substitution
"

Which is expected/desired.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 miken32
Solution 3
Solution 4 morphles