Skip to content
Advertisement

Use php exec to launch a linux command with brace expansion

How can I force the php exec() to interpret the linux brace expansion?

I am encountering a strange behavior, and did not find a way to fix it the way I want.

I want to execute a linux command containing brace expression to select a batch of files,

from php

I am using php to generate a “random” number of files, and want then to execute a shell script which will make something with the files.

Here is my bash version:

“$ echo $BASH_VERSION”

4.1.5(1)-release

To give a simple example, let’s assume I create the following files:

touch /tmp/file_{1..12}.xml


shell.sh

#!/bin/sh
FILES=$*
echo "nnFILES: $FILES"
for f in $FILES; do
  echo Posting file $f
done

test.php

<?php
$cmd = "./shell.sh /tmp/file_{1..12}.xml";
echo"nnCOMMAND:n".$cmd."nn";
var_dump(shell_exec($cmd));

The output of “php test.php” is:

COMMAND:
./shell.sh /tmp/file_{1..12}.xml
string(66) "
FILES: /tmp/file_{1..12}.xml
Posting file /tmp/file_{1..12}.xml
"

I expect to have the same as if I run “./shell.sh /tmp/file_{1..12}.xml” from linux terminal:

$ ./shell.sh /tmp/file_{1..12}.xml

FILES: /tmp/file_1.xml /tmp/file_2.xml /tmp/file_3.xml /tmp/file_4.xml /tmp/file_5.xml /tmp/file_6.xml /tmp/file_7.xml /tmp/file_8.xml /tmp/file_9.xml /tmp/file_10.xml /tmp/file_11.xml /tmp/file_12.xml

Posting file /tmp/file_1.xml

Posting file /tmp/file_2.xml

Posting file /tmp/file_3.xml

Posting file /tmp/file_4.xml

Posting file /tmp/file_5.xml

Posting file /tmp/file_6.xml

Posting file /tmp/file_7.xml

Posting file /tmp/file_8.xml

Posting file /tmp/file_9.xml

Posting file /tmp/file_10.xml

Posting file /tmp/file_11.xml

Posting file /tmp/file_12.xml

But I also tried with or without escapeshellcmd() with exec($cmd) AND other functions like system() or eval()… None of them did the job…

I know that I could do the foreach loop in php, but I am sure there is a way to have this command interpreted as if it was launched from command line.

Advertisement

Answer

  • As @Josh Trii Johnston has pointed out, the ‘outer’ shell you are implicitly using to call your shell script using shell_exec() is probably not Bash in your case. This way, brace expansion never takes place because there is no shell capable of expanding the expression before calling your program (as it would be in an interactive Bash session).

    You could

    • try to change the shell invoked by PHP’s shell_exec(), but this may not be possible
    • call /bin/bash with your program and the brace expression instead of only the brace expression: $cmd = "/bin/bash -c './shell.sh /tmp/file_{1..12}.xml'";
    • use eval on the argument inside your script to expand the brace expression.
  • From the bash(1) man page:

    If bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well. […] When invoked as sh, bash enters posix mode after the startup files are read.

    Try changing

    #!/bin/sh
    

    to

    #!/bin/bash
    

    if you expect Bash behavior (there is no brace expansion in POSIX).

  • If all of the above does not help, you should make sure that brace expansion is activated by executing set -o (while calling your program from the PHP script). If it is off, you can turn it on using:

    set -o braceexpand
    
Advertisement