0

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)
3
  • Which shell are you using for testing, and which one is linked as /bin/sh? dash does not support expression pipes AFAIK. Commented Jul 27, 2018 at 17:38
  • I did "which sh" at the command line and it returned /bin/sh. I added this line to my script, exec("which sh",$throwaway); var_dump($throwaway); and it returned /bin/sh as well. I've used pipes in commands I execute in php exec before. Commented Jul 27, 2018 at 17:49
  • Is the issue specific to comm? Or to Linux? Also check the description of the "shell" tag. That said, your question is off-topic because it really lacks a minimal reproducible example. Commented Jul 27, 2018 at 19:39

4 Answers 4

3

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 '…'.

Sign up to request clarification or add additional context in comments.

6 Comments

Did you mean to type "dash" above there?
mario-It's not clear what I need to do with what you're saying in your answer.
Even when sh is bash, it'll run in a compatibility more where process substitution is not available
@thatotherguy So it'll only work for real login or interactive shells? // Then -l or +o restricted might be necessary.
No, it's fine in non-interactive shells. It just requires that bash is invoked as bash, such as with bash -c
|
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.

5 Comments

I tried this, and running the shell script with the command has the same complaint. That's strange, since the command runs at the command line.
I find that hard to believe since the shebang tells it to run under bash. Did you mark the script executable?
Yes, I made it chmod 777. I got something to work. I moved the comm part to the shell script like you have, with bin bash at the top, and I run the shell script like this from my php script: exec("/bin/bash -c /opt/IBM/custom/NAC_Dslam/Common_list.sh", $outputShell); I also have the #!/bin/bash at the top of my php script.
BTW, the shell script ran from the command line, just not from the php script until I made those changes.
It was adding /bin/bash/ -c in front of my exec in the php script that seemed to help
0

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);

1 Comment

Are you saying to run the comm command as a shell script using #!/usr/bin/bash. I'm trying that right now, and it has the same error, when executed from my php script.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.