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.
- try to change the shell invoked by PHP’s
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